summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin')
-rw-r--r--gnu/usr.bin/Makefile6
-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.gnu356
-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.gnu133
-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.c539
-rw-r--r--gnu/usr.bin/as/append.c37
-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.h416
-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.c239
-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/a.out.gnu.h261
-rw-r--r--gnu/usr.bin/as/config/aout.h430
-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/i386-opcode.h806
-rw-r--r--gnu/usr.bin/as/config/i386.c1946
-rw-r--r--gnu/usr.bin/as/config/i386.h296
-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.c648
-rw-r--r--gnu/usr.bin/as/config/obj-aout.h210
-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.c2313
-rw-r--r--gnu/usr.bin/as/config/tc-i386.h254
-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.c4076
-rw-r--r--gnu/usr.bin/as/config/tc-m68k.h60
-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.c1923
-rw-r--r--gnu/usr.bin/as/config/tc-ns32k.h60
-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.c1766
-rw-r--r--gnu/usr.bin/as/config/tc-sparc.h54
-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/Makefile187
-rw-r--r--gnu/usr.bin/as/doc/Makefile.in172
-rw-r--r--gnu/usr.bin/as/doc/a29k-coff.m414
-rw-r--r--gnu/usr.bin/as/doc/a29k.m49
-rw-r--r--gnu/usr.bin/as/doc/all.m420
-rw-r--r--gnu/usr.bin/as/doc/as.texinfo6730
-rw-r--r--gnu/usr.bin/as/doc/config.status5
-rw-r--r--gnu/usr.bin/as/doc/configure.in34
-rw-r--r--gnu/usr.bin/as/doc/gen.m414
-rw-r--r--gnu/usr.bin/as/doc/h8.m415
-rw-r--r--gnu/usr.bin/as/doc/i80386.m412
-rw-r--r--gnu/usr.bin/as/doc/i960.m416
-rw-r--r--gnu/usr.bin/as/doc/m680x0.m48
-rw-r--r--gnu/usr.bin/as/doc/none.m457
-rw-r--r--gnu/usr.bin/as/doc/pretex.m4268
-rw-r--r--gnu/usr.bin/as/doc/sparc.m48
-rw-r--r--gnu/usr.bin/as/doc/vax.m47
-rw-r--r--gnu/usr.bin/as/doc/vintage.m411
-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-const.c157
-rw-r--r--gnu/usr.bin/as/flonum-copy.c76
-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.c436
-rw-r--r--gnu/usr.bin/as/link.cmd10
-rw-r--r--gnu/usr.bin/as/listing.c849
-rw-r--r--gnu/usr.bin/as/listing.h95
-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/md.h57
-rw-r--r--gnu/usr.bin/as/messages.c417
-rw-r--r--gnu/usr.bin/as/obj.h77
-rw-r--r--gnu/usr.bin/as/objrecdef.h255
-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.h830
-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.h1996
-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.h871
-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.c2347
-rw-r--r--gnu/usr.bin/as/read.h149
-rw-r--r--gnu/usr.bin/as/struc-symbol.h132
-rw-r--r--gnu/usr.bin/as/subsegs.c308
-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.c1213
-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.c300
-rw-r--r--gnu/usr.bin/awk/awk.1158
-rw-r--r--gnu/usr.bin/awk/awk.h115
-rw-r--r--gnu/usr.bin/awk/awk.y144
-rw-r--r--gnu/usr.bin/awk/builtin.c670
-rw-r--r--gnu/usr.bin/awk/config.h38
-rw-r--r--gnu/usr.bin/awk/dfa.c2837
-rw-r--r--gnu/usr.bin/awk/dfa.h425
-rw-r--r--gnu/usr.bin/awk/eval.c113
-rw-r--r--gnu/usr.bin/awk/field.c119
-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.c221
-rw-r--r--gnu/usr.bin/awk/iop.c27
-rw-r--r--gnu/usr.bin/awk/main.c178
-rw-r--r--gnu/usr.bin/awk/msg.c11
-rw-r--r--gnu/usr.bin/awk/node.c68
-rw-r--r--gnu/usr.bin/awk/patchlevel.h2
-rw-r--r--gnu/usr.bin/awk/protos.h45
-rw-r--r--gnu/usr.bin/awk/re.c46
-rw-r--r--gnu/usr.bin/awk/regex.c6330
-rw-r--r--gnu/usr.bin/awk/regex.h675
-rw-r--r--gnu/usr.bin/awk/version.c3
-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/Makefile72
-rw-r--r--gnu/usr.bin/binutils/gdb/gdb.1371
-rw-r--r--gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c323
-rw-r--r--gnu/usr.bin/binutils/gdb/i386/nm.h44
-rw-r--r--gnu/usr.bin/binutils/gdb/i386/tm.h76
-rw-r--r--gnu/usr.bin/binutils/gdb/i386/version.c3
-rw-r--r--gnu/usr.bin/binutils/gdb/i386/xm.h31
-rw-r--r--gnu/usr.bin/cc/cccp/Makefile12
-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/Makefile9
-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.c801
-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.h176
-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/main.c479
-rw-r--r--gnu/usr.bin/cpio/makepath.c297
-rw-r--r--gnu/usr.bin/cpio/mt.1107
-rw-r--r--gnu/usr.bin/cpio/rmt.c281
-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/Makefile3
-rw-r--r--gnu/usr.bin/cvs/contrib/README68
-rw-r--r--gnu/usr.bin/cvs/contrib/cln_hist.pl91
-rw-r--r--gnu/usr.bin/cvs/contrib/commit_prep.pl168
-rw-r--r--gnu/usr.bin/cvs/contrib/cvs_acls.pl142
-rw-r--r--gnu/usr.bin/cvs/contrib/cvscheck84
-rw-r--r--gnu/usr.bin/cvs/contrib/cvscheck.man53
-rw-r--r--gnu/usr.bin/cvs/contrib/cvshelp.man562
-rw-r--r--gnu/usr.bin/cvs/contrib/descend116
-rw-r--r--gnu/usr.bin/cvs/contrib/descend.man115
-rw-r--r--gnu/usr.bin/cvs/contrib/dirfns481
-rw-r--r--gnu/usr.bin/cvs/contrib/log.pl104
-rw-r--r--gnu/usr.bin/cvs/contrib/log_accum.pl331
-rw-r--r--gnu/usr.bin/cvs/contrib/mfpipe.pl87
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog119
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL83
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile78
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/README14
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el52
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el884
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el298
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el386
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el89
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el6
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el1476
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info1367
-rw-r--r--gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo1437
-rw-r--r--gnu/usr.bin/cvs/contrib/rcs-to-cvs208
-rw-r--r--gnu/usr.bin/cvs/contrib/rcslock.pl234
-rw-r--r--gnu/usr.bin/cvs/contrib/sccs2rcs277
-rw-r--r--gnu/usr.bin/cvs/cvs/Makefile36
-rw-r--r--gnu/usr.bin/cvs/cvs/add.c447
-rw-r--r--gnu/usr.bin/cvs/cvs/admin.c124
-rw-r--r--gnu/usr.bin/cvs/cvs/checkin.c142
-rw-r--r--gnu/usr.bin/cvs/cvs/checkout.c730
-rw-r--r--gnu/usr.bin/cvs/cvs/classify.c380
-rw-r--r--gnu/usr.bin/cvs/cvs/commit.c1229
-rw-r--r--gnu/usr.bin/cvs/cvs/config.h217
-rw-r--r--gnu/usr.bin/cvs/cvs/create_adm.c100
-rw-r--r--gnu/usr.bin/cvs/cvs/cvs.11991
-rw-r--r--gnu/usr.bin/cvs/cvs/cvs.5326
-rw-r--r--gnu/usr.bin/cvs/cvs/cvs.h442
-rw-r--r--gnu/usr.bin/cvs/cvs/diff.c429
-rw-r--r--gnu/usr.bin/cvs/cvs/entries.c488
-rw-r--r--gnu/usr.bin/cvs/cvs/find_names.c272
-rw-r--r--gnu/usr.bin/cvs/cvs/history.c1373
-rw-r--r--gnu/usr.bin/cvs/cvs/ignore.c227
-rw-r--r--gnu/usr.bin/cvs/cvs/import.c1011
-rw-r--r--gnu/usr.bin/cvs/cvs/lock.c522
-rw-r--r--gnu/usr.bin/cvs/cvs/log.c132
-rw-r--r--gnu/usr.bin/cvs/cvs/logmsg.c449
-rw-r--r--gnu/usr.bin/cvs/cvs/main.c460
-rw-r--r--gnu/usr.bin/cvs/cvs/modules.c810
-rw-r--r--gnu/usr.bin/cvs/cvs/no_diff.c85
-rw-r--r--gnu/usr.bin/cvs/cvs/parseinfo.c147
-rw-r--r--gnu/usr.bin/cvs/cvs/patch.c541
-rw-r--r--gnu/usr.bin/cvs/cvs/patchlevel.h1
-rw-r--r--gnu/usr.bin/cvs/cvs/rcs.c1449
-rw-r--r--gnu/usr.bin/cvs/cvs/rcs.h102
-rw-r--r--gnu/usr.bin/cvs/cvs/recurse.c535
-rw-r--r--gnu/usr.bin/cvs/cvs/release.c223
-rw-r--r--gnu/usr.bin/cvs/cvs/remove.c176
-rw-r--r--gnu/usr.bin/cvs/cvs/repos.c169
-rw-r--r--gnu/usr.bin/cvs/cvs/rtag.c403
-rw-r--r--gnu/usr.bin/cvs/cvs/status.c230
-rw-r--r--gnu/usr.bin/cvs/cvs/tag.c263
-rw-r--r--gnu/usr.bin/cvs/cvs/update.c1076
-rw-r--r--gnu/usr.bin/cvs/cvs/vers_ts.c224
-rw-r--r--gnu/usr.bin/cvs/cvs/version.c11
-rw-r--r--gnu/usr.bin/cvs/doc/cvs.ms1073
-rw-r--r--gnu/usr.bin/cvs/examples/commitinfo21
-rw-r--r--gnu/usr.bin/cvs/examples/editinfo30
-rw-r--r--gnu/usr.bin/cvs/examples/loginfo20
-rw-r--r--gnu/usr.bin/cvs/examples/modules566
-rw-r--r--gnu/usr.bin/cvs/examples/rcsinfo18
-rw-r--r--gnu/usr.bin/cvs/lib/Makefile13
-rw-r--r--gnu/usr.bin/cvs/lib/Makefile.in91
-rw-r--r--gnu/usr.bin/cvs/lib/alloca.c191
-rw-r--r--gnu/usr.bin/cvs/lib/argmatch.c83
-rw-r--r--gnu/usr.bin/cvs/lib/dup2.c36
-rw-r--r--gnu/usr.bin/cvs/lib/error.c193
-rw-r--r--gnu/usr.bin/cvs/lib/fnmatch.c183
-rw-r--r--gnu/usr.bin/cvs/lib/fnmatch.h45
-rw-r--r--gnu/usr.bin/cvs/lib/ftruncate.c72
-rw-r--r--gnu/usr.bin/cvs/lib/getdate.y889
-rw-r--r--gnu/usr.bin/cvs/lib/getopt.c604
-rw-r--r--gnu/usr.bin/cvs/lib/getopt.h102
-rw-r--r--gnu/usr.bin/cvs/lib/getopt1.c166
-rw-r--r--gnu/usr.bin/cvs/lib/getwd.c31
-rw-r--r--gnu/usr.bin/cvs/lib/hash.c338
-rw-r--r--gnu/usr.bin/cvs/lib/hash.h77
-rw-r--r--gnu/usr.bin/cvs/lib/mkdir.c125
-rw-r--r--gnu/usr.bin/cvs/lib/myndbm.c212
-rw-r--r--gnu/usr.bin/cvs/lib/myndbm.h44
-rw-r--r--gnu/usr.bin/cvs/lib/regex.c4867
-rw-r--r--gnu/usr.bin/cvs/lib/regex.h479
-rw-r--r--gnu/usr.bin/cvs/lib/rename.c68
-rw-r--r--gnu/usr.bin/cvs/lib/sighandle.c412
-rw-r--r--gnu/usr.bin/cvs/lib/strdup.c39
-rw-r--r--gnu/usr.bin/cvs/lib/strippath.c74
-rw-r--r--gnu/usr.bin/cvs/lib/stripslash.c35
-rw-r--r--gnu/usr.bin/cvs/lib/subr.c912
-rw-r--r--gnu/usr.bin/cvs/lib/system.h223
-rw-r--r--gnu/usr.bin/cvs/lib/wait.h29
-rw-r--r--gnu/usr.bin/cvs/lib/y.tab.h18
-rw-r--r--gnu/usr.bin/cvs/lib/yesno.c37
-rw-r--r--gnu/usr.bin/cvs/mkmodules/Makefile12
-rw-r--r--gnu/usr.bin/cvs/mkmodules/mkmodules.165
-rw-r--r--gnu/usr.bin/cvs/mkmodules/mkmodules.c395
-rw-r--r--gnu/usr.bin/cvs/mkmodules/xxx5320
-rw-r--r--gnu/usr.bin/dc/COPYING339
-rw-r--r--gnu/usr.bin/dc/ChangeLog77
-rw-r--r--gnu/usr.bin/dc/Makefile7
-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.c909
-rw-r--r--gnu/usr.bin/dc/dc.info330
-rw-r--r--gnu/usr.bin/dc/dc.texinfo381
-rw-r--r--gnu/usr.bin/dc/decimal.c1235
-rw-r--r--gnu/usr.bin/dc/decimal.h93
-rw-r--r--gnu/usr.bin/diff/COPYING339
-rw-r--r--gnu/usr.bin/diff/Makefile8
-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.h112
-rw-r--r--gnu/usr.bin/diff/context.c464
-rw-r--r--gnu/usr.bin/diff/diff.1473
-rw-r--r--gnu/usr.bin/diff/diff.c997
-rw-r--r--gnu/usr.bin/diff/diff.h348
-rw-r--r--gnu/usr.bin/diff/diff3.c1707
-rw-r--r--gnu/usr.bin/diff/dir.c216
-rw-r--r--gnu/usr.bin/diff/ed.c200
-rw-r--r--gnu/usr.bin/diff/fnmatch.h62
-rw-r--r--gnu/usr.bin/diff/getopt.c757
-rw-r--r--gnu/usr.bin/diff/getopt.h129
-rw-r--r--gnu/usr.bin/diff/getopt1.c187
-rw-r--r--gnu/usr.bin/diff/ifdef.c428
-rw-r--r--gnu/usr.bin/diff/io.c666
-rw-r--r--gnu/usr.bin/diff/normal.c71
-rw-r--r--gnu/usr.bin/diff/regex.c5171
-rw-r--r--gnu/usr.bin/diff/regex.h490
-rw-r--r--gnu/usr.bin/diff/sdiff.c1193
-rw-r--r--gnu/usr.bin/diff/side.c284
-rw-r--r--gnu/usr.bin/diff/system.h215
-rw-r--r--gnu/usr.bin/diff/util.c744
-rw-r--r--gnu/usr.bin/diff/version.c5
-rw-r--r--gnu/usr.bin/diff3/COPYING339
-rw-r--r--gnu/usr.bin/diff3/Makefile8
-rw-r--r--gnu/usr.bin/diff3/diff3.1207
-rw-r--r--gnu/usr.bin/diff3/diff3.c1693
-rw-r--r--gnu/usr.bin/diff3/getopt.c731
-rw-r--r--gnu/usr.bin/diff3/getopt.h129
-rw-r--r--gnu/usr.bin/diff3/getopt1.c176
-rw-r--r--gnu/usr.bin/diff3/system.h159
-rw-r--r--gnu/usr.bin/diff3/version.c3
-rw-r--r--gnu/usr.bin/gdb/COPYING339
-rw-r--r--gnu/usr.bin/gdb/COPYING.LIB481
-rw-r--r--gnu/usr.bin/gdb/ChangeLog4887
-rw-r--r--gnu/usr.bin/gdb/Gdbinit15
-rw-r--r--gnu/usr.bin/gdb/Makefile3
-rw-r--r--gnu/usr.bin/gdb/Makefile.dist371
-rw-r--r--gnu/usr.bin/gdb/Projects114
-rw-r--r--gnu/usr.bin/gdb/README.FreeBSD15
-rw-r--r--gnu/usr.bin/gdb/README.gnu142
-rw-r--r--gnu/usr.bin/gdb/VERSION1
-rw-r--r--gnu/usr.bin/gdb/XGdbinit.samp15
-rw-r--r--gnu/usr.bin/gdb/Xgdb.ad8
-rw-r--r--gnu/usr.bin/gdb/bfd/COPYING339
-rw-r--r--gnu/usr.bin/gdb/bfd/Makefile17
-rw-r--r--gnu/usr.bin/gdb/bfd/README.FreeBSD7
-rw-r--r--gnu/usr.bin/gdb/bfd/VERSION1
-rw-r--r--gnu/usr.bin/gdb/bfd/aout-target.h429
-rw-r--r--gnu/usr.bin/gdb/bfd/aout32.c23
-rw-r--r--gnu/usr.bin/gdb/bfd/aoutx.h2568
-rw-r--r--gnu/usr.bin/gdb/bfd/archive.c1770
-rw-r--r--gnu/usr.bin/gdb/bfd/archures.c731
-rw-r--r--gnu/usr.bin/gdb/bfd/bfd.c733
-rw-r--r--gnu/usr.bin/gdb/bfd/bfd.h1803
-rw-r--r--gnu/usr.bin/gdb/bfd/cache.c311
-rw-r--r--gnu/usr.bin/gdb/bfd/coffgen.c1519
-rw-r--r--gnu/usr.bin/gdb/bfd/core.c106
-rw-r--r--gnu/usr.bin/gdb/bfd/cpu-i386.c43
-rw-r--r--gnu/usr.bin/gdb/bfd/ctor.c148
-rw-r--r--gnu/usr.bin/gdb/bfd/ecoff.c3994
-rw-r--r--gnu/usr.bin/gdb/bfd/elf.c248
-rw-r--r--gnu/usr.bin/gdb/bfd/format.c258
-rw-r--r--gnu/usr.bin/gdb/bfd/freebsd386.c110
-rw-r--r--gnu/usr.bin/gdb/bfd/init.c78
-rw-r--r--gnu/usr.bin/gdb/bfd/libaout.h393
-rw-r--r--gnu/usr.bin/gdb/bfd/libbfd.c850
-rw-r--r--gnu/usr.bin/gdb/bfd/libbfd.h273
-rw-r--r--gnu/usr.bin/gdb/bfd/libcoff.h352
-rw-r--r--gnu/usr.bin/gdb/bfd/libecoff.h265
-rw-r--r--gnu/usr.bin/gdb/bfd/libelf.h249
-rw-r--r--gnu/usr.bin/gdb/bfd/opncls.c534
-rw-r--r--gnu/usr.bin/gdb/bfd/reloc.c1225
-rw-r--r--gnu/usr.bin/gdb/bfd/seclet.c185
-rw-r--r--gnu/usr.bin/gdb/bfd/seclet.h55
-rw-r--r--gnu/usr.bin/gdb/bfd/section.c899
-rw-r--r--gnu/usr.bin/gdb/bfd/srec.c1001
-rw-r--r--gnu/usr.bin/gdb/bfd/stab-syms.c59
-rw-r--r--gnu/usr.bin/gdb/bfd/syms.c527
-rw-r--r--gnu/usr.bin/gdb/bfd/sysdep.h47
-rw-r--r--gnu/usr.bin/gdb/bfd/targets.c635
-rw-r--r--gnu/usr.bin/gdb/bfd/trad-core.c384
-rw-r--r--gnu/usr.bin/gdb/blockframe.c622
-rw-r--r--gnu/usr.bin/gdb/breakpoint.c1383
-rw-r--r--gnu/usr.bin/gdb/command.c856
-rw-r--r--gnu/usr.bin/gdb/command.h77
-rw-r--r--gnu/usr.bin/gdb/config/Makefile.i3866
-rw-r--r--gnu/usr.bin/gdb/config/default-dep.c585
-rw-r--r--gnu/usr.bin/gdb/config/i386-dep.c1275
-rw-r--r--gnu/usr.bin/gdb/config/i386-pinsn.c1812
-rw-r--r--gnu/usr.bin/gdb/config/i386bsd-dep.c1889
-rw-r--r--gnu/usr.bin/gdb/config/m-i386-sv32.h28
-rw-r--r--gnu/usr.bin/gdb/config/m-i386.h394
-rw-r--r--gnu/usr.bin/gdb/config/m-i386bsd.h375
-rw-r--r--gnu/usr.bin/gdb/config/m-i386g-sv32.h28
-rw-r--r--gnu/usr.bin/gdb/config/m-i386gas.h37
-rw-r--r--gnu/usr.bin/gdb/copying.c215
-rw-r--r--gnu/usr.bin/gdb/core.c581
-rw-r--r--gnu/usr.bin/gdb/cplus-dem.c996
-rw-r--r--gnu/usr.bin/gdb/dbxread.c5727
-rw-r--r--gnu/usr.bin/gdb/defs.h122
-rw-r--r--gnu/usr.bin/gdb/doc/ChangeLog783
-rw-r--r--gnu/usr.bin/gdb/doc/Makefile340
-rw-r--r--gnu/usr.bin/gdb/doc/Makefile.in327
-rw-r--r--gnu/usr.bin/gdb/doc/a4rc.sed11
-rw-r--r--gnu/usr.bin/gdb/doc/all-cfg.texi117
-rwxr-xr-xgnu/usr.bin/gdb/doc/config.status5
-rw-r--r--gnu/usr.bin/gdb/doc/configure.in7
-rw-r--r--gnu/usr.bin/gdb/doc/gdb-cfg.texi117
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info213
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-11304
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-21165
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-31264
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-41349
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-51215
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-61220
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-71233
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.info-8657
-rw-r--r--gnu/usr.bin/gdb/doc/gdb.texinfo8591
-rw-r--r--gnu/usr.bin/gdb/doc/gdbint.texinfo2658
-rw-r--r--gnu/usr.bin/gdb/doc/h8-cfg.texi47
-rw-r--r--gnu/usr.bin/gdb/doc/libgdb.texinfo1471
-rw-r--r--gnu/usr.bin/gdb/doc/lpsrc.sed13
-rw-r--r--gnu/usr.bin/gdb/doc/psrc.sed13
-rw-r--r--gnu/usr.bin/gdb/doc/refcard.ps798
-rw-r--r--gnu/usr.bin/gdb/doc/refcard.tex646
-rw-r--r--gnu/usr.bin/gdb/doc/remote.texi1294
-rw-r--r--gnu/usr.bin/gdb/doc/stabs.texinfo3795
-rw-r--r--gnu/usr.bin/gdb/environ.c185
-rw-r--r--gnu/usr.bin/gdb/environ.h39
-rw-r--r--gnu/usr.bin/gdb/eval.c1065
-rw-r--r--gnu/usr.bin/gdb/expprint.c324
-rw-r--r--gnu/usr.bin/gdb/expread.y1782
-rw-r--r--gnu/usr.bin/gdb/expression.h191
-rw-r--r--gnu/usr.bin/gdb/findvar.c579
-rw-r--r--gnu/usr.bin/gdb/frame.h115
-rw-r--r--gnu/usr.bin/gdb/gdb.13
-rw-r--r--gnu/usr.bin/gdb/gdb/COPYING339
-rw-r--r--gnu/usr.bin/gdb/gdb/Makefile72
-rw-r--r--gnu/usr.bin/gdb/gdb/ansidecl.h139
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/aout64.h431
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/ar.h32
-rw-r--r--gnu/usr.bin/gdb/gdb/aout/ranlib.h62
-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/blockframe.c821
-rw-r--r--gnu/usr.bin/gdb/gdb/breakpoint.c3301
-rw-r--r--gnu/usr.bin/gdb/gdb/breakpoint.h372
-rw-r--r--gnu/usr.bin/gdb/gdb/buildsym.c950
-rw-r--r--gnu/usr.bin/gdb/gdb/buildsym.h259
-rw-r--r--gnu/usr.bin/gdb/gdb/c-exp.tab.c2648
-rw-r--r--gnu/usr.bin/gdb/gdb/c-exp.y1601
-rw-r--r--gnu/usr.bin/gdb/gdb/c-lang.c447
-rw-r--r--gnu/usr.bin/gdb/gdb/c-lang.h31
-rw-r--r--gnu/usr.bin/gdb/gdb/c-typeprint.c797
-rw-r--r--gnu/usr.bin/gdb/gdb/c-valprint.c416
-rw-r--r--gnu/usr.bin/gdb/gdb/call-cmds.h28
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-exp.tab.c2854
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-exp.y1997
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-lang.c341
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-lang.h31
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-typeprint.c225
-rw-r--r--gnu/usr.bin/gdb/gdb/ch-valprint.c332
-rw-r--r--gnu/usr.bin/gdb/gdb/coff/ecoff.h262
-rw-r--r--gnu/usr.bin/gdb/gdb/coff/internal.h538
-rw-r--r--gnu/usr.bin/gdb/gdb/coff/sym.h477
-rw-r--r--gnu/usr.bin/gdb/gdb/coff/symconst.h175
-rw-r--r--gnu/usr.bin/gdb/gdb/coffread.c2071
-rw-r--r--gnu/usr.bin/gdb/gdb/command.c1310
-rw-r--r--gnu/usr.bin/gdb/gdb/command.h241
-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.c291
-rw-r--r--gnu/usr.bin/gdb/gdb/coredep.c118
-rw-r--r--gnu/usr.bin/gdb/gdb/corelow.c328
-rw-r--r--gnu/usr.bin/gdb/gdb/cp-valprint.c484
-rw-r--r--gnu/usr.bin/gdb/gdb/dbxread.c2234
-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.h901
-rw-r--r--gnu/usr.bin/gdb/gdb/demangle.c190
-rw-r--r--gnu/usr.bin/gdb/gdb/demangle.h77
-rw-r--r--gnu/usr.bin/gdb/gdb/dis-asm.h176
-rw-r--r--gnu/usr.bin/gdb/gdb/dis-buf.c69
-rw-r--r--gnu/usr.bin/gdb/gdb/dwarfread.c3866
-rw-r--r--gnu/usr.bin/gdb/gdb/elf/common.h216
-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.h195
-rw-r--r--gnu/usr.bin/gdb/gdb/elfread.c729
-rw-r--r--gnu/usr.bin/gdb/gdb/environ.c198
-rw-r--r--gnu/usr.bin/gdb/gdb/environ.h58
-rw-r--r--gnu/usr.bin/gdb/gdb/eval.c1213
-rw-r--r--gnu/usr.bin/gdb/gdb/exec.c489
-rw-r--r--gnu/usr.bin/gdb/gdb/expprint.c623
-rw-r--r--gnu/usr.bin/gdb/gdb/expression.h313
-rw-r--r--gnu/usr.bin/gdb/gdb/findvar.c971
-rw-r--r--gnu/usr.bin/gdb/gdb/fopen-same.h27
-rw-r--r--gnu/usr.bin/gdb/gdb/fork-child.c310
-rw-r--r--gnu/usr.bin/gdb/gdb/frame.h238
-rw-r--r--gnu/usr.bin/gdb/gdb/freebsd-nat.c323
-rw-r--r--gnu/usr.bin/gdb/gdb/freebsd-solib.c1469
-rw-r--r--gnu/usr.bin/gdb/gdb/gdb-stabs.h76
-rw-r--r--gnu/usr.bin/gdb/gdb/gdb.1371
-rw-r--r--gnu/usr.bin/gdb/gdb/gdbcmd.h101
-rw-r--r--gnu/usr.bin/gdb/gdb/gdbcore.h129
-rw-r--r--gnu/usr.bin/gdb/gdb/gdbtypes.c1440
-rw-r--r--gnu/usr.bin/gdb/gdb/gdbtypes.h704
-rw-r--r--gnu/usr.bin/gdb/gdb/getopt.h129
-rw-r--r--gnu/usr.bin/gdb/gdb/i386-dis.c1952
-rw-r--r--gnu/usr.bin/gdb/gdb/i386-pinsn.c37
-rw-r--r--gnu/usr.bin/gdb/gdb/i386-tdep.c595
-rw-r--r--gnu/usr.bin/gdb/gdb/infcmd.c1423
-rw-r--r--gnu/usr.bin/gdb/gdb/inferior.h401
-rw-r--r--gnu/usr.bin/gdb/gdb/inflow.c662
-rw-r--r--gnu/usr.bin/gdb/gdb/infptrace.c436
-rw-r--r--gnu/usr.bin/gdb/gdb/infrun.c1848
-rw-r--r--gnu/usr.bin/gdb/gdb/inftarg.c310
-rw-r--r--gnu/usr.bin/gdb/gdb/init.c47
-rw-r--r--gnu/usr.bin/gdb/gdb/language.c1332
-rw-r--r--gnu/usr.bin/gdb/gdb/language.h413
-rw-r--r--gnu/usr.bin/gdb/gdb/m2-exp.tab.c1991
-rw-r--r--gnu/usr.bin/gdb/gdb/m2-exp.y1169
-rw-r--r--gnu/usr.bin/gdb/gdb/m2-lang.c457
-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.c2799
-rw-r--r--gnu/usr.bin/gdb/gdb/maint.c305
-rw-r--r--gnu/usr.bin/gdb/gdb/mem-break.c104
-rw-r--r--gnu/usr.bin/gdb/gdb/minsyms.c597
-rw-r--r--gnu/usr.bin/gdb/gdb/mipsread.c3653
-rw-r--r--gnu/usr.bin/gdb/gdb/nlmread.c300
-rw-r--r--gnu/usr.bin/gdb/gdb/nm.h44
-rw-r--r--gnu/usr.bin/gdb/gdb/objfiles.c773
-rw-r--r--gnu/usr.bin/gdb/gdb/objfiles.h437
-rw-r--r--gnu/usr.bin/gdb/gdb/obstack.h490
-rw-r--r--gnu/usr.bin/gdb/gdb/parse.c827
-rw-r--r--gnu/usr.bin/gdb/gdb/parser-defs.h188
-rw-r--r--gnu/usr.bin/gdb/gdb/partial-stab.h618
-rw-r--r--gnu/usr.bin/gdb/gdb/printcmd.c2078
-rw-r--r--gnu/usr.bin/gdb/gdb/putenv.c111
-rw-r--r--gnu/usr.bin/gdb/gdb/regex.c1725
-rw-r--r--gnu/usr.bin/gdb/gdb/regex.h179
-rw-r--r--gnu/usr.bin/gdb/gdb/remote-utils.c645
-rw-r--r--gnu/usr.bin/gdb/gdb/remote-utils.h149
-rw-r--r--gnu/usr.bin/gdb/gdb/remote.c1272
-rw-r--r--gnu/usr.bin/gdb/gdb/ser-unix.c633
-rw-r--r--gnu/usr.bin/gdb/gdb/serial.c261
-rw-r--r--gnu/usr.bin/gdb/gdb/serial.h153
-rw-r--r--gnu/usr.bin/gdb/gdb/signals.h27
-rw-r--r--gnu/usr.bin/gdb/gdb/solib.h56
-rw-r--r--gnu/usr.bin/gdb/gdb/source.c1398
-rw-r--r--gnu/usr.bin/gdb/gdb/stabsread.c3770
-rw-r--r--gnu/usr.bin/gdb/gdb/stabsread.h194
-rw-r--r--gnu/usr.bin/gdb/gdb/stack.c1379
-rw-r--r--gnu/usr.bin/gdb/gdb/symfile.c1489
-rw-r--r--gnu/usr.bin/gdb/gdb/symfile.h228
-rw-r--r--gnu/usr.bin/gdb/gdb/symmisc.c857
-rw-r--r--gnu/usr.bin/gdb/gdb/symtab.c3035
-rw-r--r--gnu/usr.bin/gdb/gdb/symtab.h1124
-rw-r--r--gnu/usr.bin/gdb/gdb/target.c789
-rw-r--r--gnu/usr.bin/gdb/gdb/target.h465
-rw-r--r--gnu/usr.bin/gdb/gdb/terminal.h62
-rw-r--r--gnu/usr.bin/gdb/gdb/thread.c248
-rw-r--r--gnu/usr.bin/gdb/gdb/thread.h36
-rw-r--r--gnu/usr.bin/gdb/gdb/tm-i386v.h309
-rw-r--r--gnu/usr.bin/gdb/gdb/tm.h76
-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.c1547
-rw-r--r--gnu/usr.bin/gdb/gdb/valarith.c969
-rw-r--r--gnu/usr.bin/gdb/gdb/valops.c1819
-rw-r--r--gnu/usr.bin/gdb/gdb/valprint.c1063
-rw-r--r--gnu/usr.bin/gdb/gdb/valprint.h40
-rw-r--r--gnu/usr.bin/gdb/gdb/value.h502
-rw-r--r--gnu/usr.bin/gdb/gdb/values.c1502
-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.h31
-rw-r--r--gnu/usr.bin/gdb/gdb/y.tab.h65
-rw-r--r--gnu/usr.bin/gdb/getpagesize.h25
-rw-r--r--gnu/usr.bin/gdb/infcmd.c1204
-rw-r--r--gnu/usr.bin/gdb/inferior.h142
-rw-r--r--gnu/usr.bin/gdb/inflow.c569
-rw-r--r--gnu/usr.bin/gdb/infrun.c1459
-rw-r--r--gnu/usr.bin/gdb/kgdb_proto.h63
-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.FreeBSD7
-rw-r--r--gnu/usr.bin/gdb/libiberty/alloca-conf.h11
-rw-r--r--gnu/usr.bin/gdb/libiberty/argv.c332
-rw-r--r--gnu/usr.bin/gdb/libiberty/basename.c56
-rw-r--r--gnu/usr.bin/gdb/libiberty/concat.c118
-rw-r--r--gnu/usr.bin/gdb/libiberty/config.h1
-rw-r--r--gnu/usr.bin/gdb/libiberty/cplus-dem.c2669
-rw-r--r--gnu/usr.bin/gdb/libiberty/fdmatch.c71
-rw-r--r--gnu/usr.bin/gdb/libiberty/getopt.c750
-rw-r--r--gnu/usr.bin/gdb/libiberty/getopt1.c180
-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.c460
-rw-r--r--gnu/usr.bin/gdb/libiberty/sigsetmask.c44
-rw-r--r--gnu/usr.bin/gdb/libiberty/spaces.c67
-rw-r--r--gnu/usr.bin/gdb/libiberty/strerror.c811
-rw-r--r--gnu/usr.bin/gdb/libiberty/strsignal.c634
-rw-r--r--gnu/usr.bin/gdb/libiberty/xmalloc.c58
-rw-r--r--gnu/usr.bin/gdb/main.c2241
-rw-r--r--gnu/usr.bin/gdb/mmalloc/Makefile10
-rw-r--r--gnu/usr.bin/gdb/mmalloc/README.FreeBSD7
-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/gdb/ngdb.i386/Makefile27
-rw-r--r--gnu/usr.bin/gdb/obstack.c313
-rw-r--r--gnu/usr.bin/gdb/obstack.h372
-rw-r--r--gnu/usr.bin/gdb/printcmd.c1867
-rw-r--r--gnu/usr.bin/gdb/readline/ChangeLog98
-rw-r--r--gnu/usr.bin/gdb/readline/Makefile.gnu114
-rw-r--r--gnu/usr.bin/gdb/readline/chardefs.h50
-rw-r--r--gnu/usr.bin/gdb/readline/emacs_keymap.c472
-rw-r--r--gnu/usr.bin/gdb/readline/funmap.c217
-rw-r--r--gnu/usr.bin/gdb/readline/history.c1462
-rw-r--r--gnu/usr.bin/gdb/readline/history.h108
-rw-r--r--gnu/usr.bin/gdb/readline/keymaps.c172
-rw-r--r--gnu/usr.bin/gdb/readline/keymaps.h53
-rw-r--r--gnu/usr.bin/gdb/readline/readline.c5557
-rw-r--r--gnu/usr.bin/gdb/readline/readline.h161
-rw-r--r--gnu/usr.bin/gdb/readline/vi_keymap.c484
-rw-r--r--gnu/usr.bin/gdb/readline/vi_mode.c875
-rw-r--r--gnu/usr.bin/gdb/regex.c1738
-rw-r--r--gnu/usr.bin/gdb/regex.h185
-rw-r--r--gnu/usr.bin/gdb/remote-sl.c10
-rw-r--r--gnu/usr.bin/gdb/remote.c626
-rw-r--r--gnu/usr.bin/gdb/source.c1166
-rw-r--r--gnu/usr.bin/gdb/stab.def115
-rw-r--r--gnu/usr.bin/gdb/stack.c960
-rw-r--r--gnu/usr.bin/gdb/symmisc.c584
-rw-r--r--gnu/usr.bin/gdb/symseg.h523
-rw-r--r--gnu/usr.bin/gdb/symtab.c2473
-rw-r--r--gnu/usr.bin/gdb/symtab.h384
-rw-r--r--gnu/usr.bin/gdb/utils.c1096
-rw-r--r--gnu/usr.bin/gdb/valarith.c690
-rw-r--r--gnu/usr.bin/gdb/valops.c1418
-rw-r--r--gnu/usr.bin/gdb/valprint.c1430
-rw-r--r--gnu/usr.bin/gdb/value.h212
-rw-r--r--gnu/usr.bin/gdb/values.c1059
-rw-r--r--gnu/usr.bin/gdb/version.c20
-rw-r--r--gnu/usr.bin/gdb/wait.h81
-rw-r--r--gnu/usr.bin/gdb/xgdb/Makefile33
-rw-r--r--gnu/usr.bin/gdb/xgdb/xgdb.c700
-rw-r--r--gnu/usr.bin/grep/AUTHORS29
-rw-r--r--gnu/usr.bin/grep/COPYING339
-rw-r--r--gnu/usr.bin/grep/Makefile14
-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.c2525
-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.1375
-rw-r--r--gnu/usr.bin/grep/grep.c826
-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/regex.c4987
-rw-r--r--gnu/usr.bin/grep/regex.h490
-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/regress.sh30
-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/gzip/COPYING339
-rw-r--r--gnu/usr.bin/gzip/ChangeLog587
-rw-r--r--gnu/usr.bin/gzip/Makefile26
-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/gzexe.in151
-rw-r--r--gnu/usr.bin/gzip/gzip.1478
-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/zcmp67
-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/Makefile19
-rw-r--r--gnu/usr.bin/ld/TODO4
-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.c17
-rw-r--r--gnu/usr.bin/ld/i386/md.c357
-rw-r--r--gnu/usr.bin/ld/i386/md.h257
-rw-r--r--gnu/usr.bin/ld/i386/mdprologue.S124
-rw-r--r--gnu/usr.bin/ld/ld.1207
-rw-r--r--gnu/usr.bin/ld/ld.1aout207
-rw-r--r--gnu/usr.bin/ld/ld.c3513
-rw-r--r--gnu/usr.bin/ld/ld.h688
-rw-r--r--gnu/usr.bin/ld/ldconfig/Makefile13
-rw-r--r--gnu/usr.bin/ld/ldconfig/ldconfig.8102
-rw-r--r--gnu/usr.bin/ld/ldconfig/ldconfig.c429
-rw-r--r--gnu/usr.bin/ld/ldd/Makefile7
-rw-r--r--gnu/usr.bin/ld/ldd/ldd.124
-rw-r--r--gnu/usr.bin/ld/ldd/ldd.c136
-rw-r--r--gnu/usr.bin/ld/lib.c843
-rw-r--r--gnu/usr.bin/ld/rrs.c1179
-rw-r--r--gnu/usr.bin/ld/rtld/Makefile25
-rw-r--r--gnu/usr.bin/ld/rtld/malloc.c482
-rw-r--r--gnu/usr.bin/ld/rtld/md-prologue.c39
-rw-r--r--gnu/usr.bin/ld/rtld/rtld.c1261
-rw-r--r--gnu/usr.bin/ld/rtld/sbrk.c101
-rw-r--r--gnu/usr.bin/ld/shlib.c279
-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.h282
-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.c719
-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.inc36
-rw-r--r--gnu/usr.bin/man/README134
-rw-r--r--gnu/usr.bin/man/TODO123
-rw-r--r--gnu/usr.bin/man/apropos/Makefile47
-rw-r--r--gnu/usr.bin/man/apropos/apropos64
-rw-r--r--gnu/usr.bin/man/apropos/apropos.127
-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/Makefile15
-rw-r--r--gnu/usr.bin/man/catman/catman36
-rw-r--r--gnu/usr.bin/man/catman/catman.sh43
-rw-r--r--gnu/usr.bin/man/lib/Makefile33
-rw-r--r--gnu/usr.bin/man/lib/config.h216
-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/Makefile17
-rw-r--r--gnu/usr.bin/man/makewhatis/makewhatis79
-rw-r--r--gnu/usr.bin/man/makewhatis/makewhatis.sh120
-rw-r--r--gnu/usr.bin/man/man/Makefile31
-rw-r--r--gnu/usr.bin/man/man/glob.c680
-rw-r--r--gnu/usr.bin/man/man/man.1132
-rw-r--r--gnu/usr.bin/man/man/man.c1430
-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/Makefile30
-rw-r--r--gnu/usr.bin/man/manpath/manpath.c520
-rw-r--r--gnu/usr.bin/man/manpath/manpath.config32
-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/Makefile44
-rw-r--r--gnu/usr.bin/man/whatis/whatis66
-rw-r--r--gnu/usr.bin/man/whatis/whatis.127
-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/patch/EXTERN.h21
-rw-r--r--gnu/usr.bin/patch/INTERN.h19
-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.h193
-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.c369
-rw-r--r--gnu/usr.bin/patch/inp.h18
-rw-r--r--gnu/usr.bin/patch/patch.1584
-rw-r--r--gnu/usr.bin/patch/patch.c967
-rw-r--r--gnu/usr.bin/patch/patchlevel.h1
-rw-r--r--gnu/usr.bin/patch/pch.c1317
-rw-r--r--gnu/usr.bin/patch/pch.h36
-rw-r--r--gnu/usr.bin/patch/util.c433
-rw-r--r--gnu/usr.bin/patch/util.h88
-rw-r--r--gnu/usr.bin/patch/version.c25
-rw-r--r--gnu/usr.bin/patch/version.h9
-rw-r--r--gnu/usr.bin/pr/COPYING339
-rw-r--r--gnu/usr.bin/pr/Makefile11
-rw-r--r--gnu/usr.bin/pr/error.c117
-rw-r--r--gnu/usr.bin/pr/getopt.c757
-rw-r--r--gnu/usr.bin/pr/getopt.h129
-rw-r--r--gnu/usr.bin/pr/getopt1.c187
-rw-r--r--gnu/usr.bin/pr/pr.1103
-rw-r--r--gnu/usr.bin/pr/pr.c1920
-rw-r--r--gnu/usr.bin/pr/system.h200
-rw-r--r--gnu/usr.bin/pr/version.c13
-rw-r--r--gnu/usr.bin/pr/version.h1
-rw-r--r--gnu/usr.bin/pr/xmalloc.c88
-rw-r--r--gnu/usr.bin/ptx/Makefile7
-rw-r--r--gnu/usr.bin/ptx/regex.h490
-rw-r--r--gnu/usr.bin/rcs/Makefile2
-rw-r--r--gnu/usr.bin/rcs/Makefile.inc8
-rw-r--r--gnu/usr.bin/rcs/ci/Makefile7
-rw-r--r--gnu/usr.bin/rcs/co/Makefile7
-rw-r--r--gnu/usr.bin/rcs/co/co.110
-rw-r--r--gnu/usr.bin/rcs/co/co.c11
-rw-r--r--gnu/usr.bin/rcs/ident/Makefile7
-rw-r--r--gnu/usr.bin/rcs/lib/Makefile15
-rw-r--r--gnu/usr.bin/rcs/lib/rcsbase.h8
-rw-r--r--gnu/usr.bin/rcs/lib/rcsedit.c11
-rw-r--r--gnu/usr.bin/rcs/lib/rcskeys.c60
-rw-r--r--gnu/usr.bin/rcs/lib/rcslex.c11
-rw-r--r--gnu/usr.bin/rcs/merge/Makefile7
-rw-r--r--gnu/usr.bin/rcs/rcs/Makefile11
-rw-r--r--gnu/usr.bin/rcs/rcsclean/Makefile7
-rw-r--r--gnu/usr.bin/rcs/rcsdiff/Makefile7
-rw-r--r--gnu/usr.bin/rcs/rcsfreeze/Makefile13
-rw-r--r--gnu/usr.bin/rcs/rcsmerge/Makefile7
-rw-r--r--gnu/usr.bin/rcs/rlog/Makefile7
-rw-r--r--gnu/usr.bin/rcs/rlog/rlog.16
-rw-r--r--gnu/usr.bin/rcs/rlog/rlog.c34
-rw-r--r--gnu/usr.bin/sdiff/Makefile9
-rw-r--r--gnu/usr.bin/sdiff/sdiff.1198
-rw-r--r--gnu/usr.bin/sort/Makefile11
-rw-r--r--gnu/usr.bin/sort/error.c13
-rw-r--r--gnu/usr.bin/sort/sort.113
-rw-r--r--gnu/usr.bin/sort/sort.c71
-rw-r--r--gnu/usr.bin/sort/system.h34
-rw-r--r--gnu/usr.bin/tar/Makefile2
-rw-r--r--gnu/usr.bin/tar/extract.c36
-rw-r--r--gnu/usr.bin/tar/tar.c3
-rw-r--r--gnu/usr.bin/tar/tar.h1
1022 files changed, 460201 insertions, 4794 deletions
diff --git a/gnu/usr.bin/Makefile b/gnu/usr.bin/Makefile
new file mode 100644
index 0000000..ac38b6c
--- /dev/null
+++ b/gnu/usr.bin/Makefile
@@ -0,0 +1,6 @@
+# $Id: Makefile,v 1.2 1994/05/06 08:19:44 alm Exp $
+
+SUBDIR= as awk bc cc cpio cvs dc diff diff3 gdb grep groff gzip kgdb ld \
+ man patch ptx pr rcs sdiff sort tar
+
+.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..9b687b9
--- /dev/null
+++ b/gnu/usr.bin/as/Makefile
@@ -0,0 +1,73 @@
+# from: @(#)Makefile 6.1 (Berkeley) 3/3/91
+# $Id: Makefile,v 1.2 1993/11/03 00:50:49 paul 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 \
+ -DPIC -DOLD_GAS -DSIGTY=void -Derror=as_fatal \
+ -DSUB_SEGMENT_ALIGN=4
+#LDADD+= -lgnumalloc
+#DPADD+= /usr/lib/libgnumalloc.a
+
+CONF_HEADERS= targ-cpu.h obj-format.h host.h targ-env.h
+
+.PATH: $(.CURDIR)/config
+
+beforedepend ${PROG}: ${CONF_HEADERS}
+
+targ-cpu.h: Makefile config/Makefile.$(MACHINE)
+ @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)
+ @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)
+ @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)
+ @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.gnu b/gnu/usr.bin/as/Makefile.gnu
new file mode 100644
index 0000000..4b81b0c
--- /dev/null
+++ b/gnu/usr.bin/as/Makefile.gnu
@@ -0,0 +1,356 @@
+# Makefile for GAS.
+# Copyright (C) 1989, 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.
+
+# This makefile may be used to make the VAX, 68020, 80386,
+# SPARC, ns32k, or i860 assembler(s).
+
+BINDIR = /usr/local/bin
+#CC=gcc
+
+# If you are on a BSD system, un-comment the next two lines, and comment out
+# the lines for SystemV and HPUX below
+G0 = -g -I. #-O -Wall
+LDFLAGS = $(CFLAGS)
+#
+# To compile gas on a System Five machine, comment out the two lines above
+# and un-comment out the next three lines
+# Comment out the -lPW on the LOADLIBES line if you are using GCC.
+# G0 = -g -I. -DUSG
+# LDFLAGS = $(CFLAGS)
+# LOADLIBES = -lmalloc -lPW
+#
+# To compile gas for HPUX, link m-hpux.h to m68k.h , and un-comment the
+# next two lines. (If you are using GCC, comment out the alloca.o part)
+# (Get alloca from the emacs distribution, or use GCC.)
+# HPUX 7.0 may have a bug in setvbuf. gas gives an error message like
+# 1:"Unknown operator" -- Statement 'NO_APP' ignored
+# if setvbuf is broken. Re-compile input-file.c (and only input-file.c
+# with -DVMS and the problem should go away.
+#
+# G0 = -g -I. -DUSG
+# LOADLIBES = alloca.o
+#
+# To compile gas for a Sequent Symmetry, comment out all the above lines,
+# and un-comment the next two lines.
+# G0 = -g -I. -DUSE_SYSTEM_HDR -DEXEC_VERSION=1
+# LOADLIBES = -lc /usr/att/lib/libc.a
+
+# If you just want to compile the vax assembler, type 'make avax'
+
+# If you just want to compile the i386 assembler, type 'make a386'
+
+# If you just want to compile the ns32k assembler, type 'make a32k'
+
+# If you just want to compile the sparc assembler, type 'make asparc'
+
+# If you just want to compile the mc68020 assembler, make sure m68k.h
+# is correctly set up, and type type 'make a68' (Except on HPUX machines,
+# where you will have to make the changes marked below before typing
+# 'make a68'
+# m68k.h should be a symbolic or hard-link to one of
+# m-sun3.h , m-hpux.h or m-generic.h
+# depending on which machine you want to compile the 68020 assembler for.
+#
+# If you want the 68k assembler to be completely compatable with the the
+# SUN one, un-comment the -DSUN_ASM_SYNTAX line below.
+#
+# If you machine does not have vfprintf, but does have _doprnt(),
+# remove the # from the -DNO_VARARGS line below.
+#
+# If the return-type of a signal-hander is void (instead of int),
+# remove the # from the -DSIGTY line below.
+#
+# To include the mc68851 mmu coprocessor instructions in the 68020 assembler,
+# remove the # from the -Dm68851 line below.
+#
+# If you want the 68020 assembler use a register prefix character, un-comment
+# the REGISTER_PREFIX line, and (maybe) change the '%' to the appropriate
+# character.
+#
+# If you want the assembler to treat .L* or ..* symbols as local, instead of
+# the usual L* symbols, un-comment the DOT_LABEL_PREFIX line.
+#
+# If you want the 80386 assembler to correctly handle fsub/fsubr and fdiv/fdivr
+# opcodes (unlike most 80386 assemblers), remove the # from
+# the -DNON_BROKEN_WORDS line below.
+#
+# To compile 80386 Gas for the Sequent Symmetry, un-comment the -DEXEC_VERSION
+# and the -DUSE_SYSTEM_HDR lines below.
+#
+# To compile gas for the HP 9000/300 un-comment the -DUSE_HP_HDR line below.
+#
+# For the ns32k, the options are 32532 or 32032 CPU and 32381 or 32081 FPU.
+# To select the NS32532, remove the # from the -DNS32532 line below.
+# To compile in tne NS32381 opcodes in addition to the NS32081 opcodes
+# (the 32381 is a superset of the 32081), remove the # from the -DNS32381
+# line below.
+#
+# For the ns32k on a Sequent, uncomment the SEQUENT_COMPATABILITY line below.
+#
+# If you want the .align N directive to align to the next N byte boundry,
+# instead of the next 1<<N boundry, un-comment the OTHER_ALIGN line below.
+# (This option is automatically enabled when building the sparc assembler.
+#
+
+O1 = -DNO_VARARGS
+O2 = # -DNON_BROKEN_WORDS
+O3 = # -Dm68851
+O4 = # -DEXEC_VERSION=1
+O5 = # -DSIGTY=void
+O6 = # -DNS32532
+O6 = # -DNS32381
+O7 = # -DDOT_LABEL_PREFIX
+O8 = # -DSEQUENT_COMPATABILITY
+O9 = # -DREGISTER_PREFIX=\'%\'
+O10= # -DOTHER_ALIGN
+
+G1 = # -DUSE_SYSTEM_HDR
+G2 = # -DUSE_HP_HDR
+G3 = # -DSUN_ASM_SYNTAX
+
+OPTIONS = $(O1) $(O2) $(O3) $(O4) $(O5) $(O6) $(O7) $(O8) $(O9) $(O10)
+
+CFLAGS = $(G0) $(G1) $(G2) $(G3) $(G4)
+
+#
+# To make the 68020 assembler compile as the default, un-comment the next
+# line, and comment out all the other lines that start with DEFAULT_GAS
+DEFAULT_GAS=a68
+#
+# To make the VAX assembler compile as the default, un-comment the next
+# line and commment out all the other lines that start with DEFAULT_GAS
+#DEFAULT_GAS=avax
+#
+# To make the 80386 assembler compile as the default, un-comment the next
+# line and commment out all the other lines that start with DEFAULT_GAS
+#DEFAULT_GAS=a386
+#
+# To make the ns32k assembler compile as the default, un-comment the next
+# line and commment out all the other lines that start with DEFAULT_GAS
+#DEFAULT_GAS=a32k
+#
+# To make the sparc assembler compile as the default, un-comment the next
+# line and commment out all the other lines that start with DEFAULT_GAS
+#DEFAULT_GAS=asparc
+#
+# To make the i860 assembler compile as the default, un-comment the next
+# line and comment out all the other lines that start with DEFAULT_GAS
+#DEFAULT_GAS=a860
+
+# Global Sources -------------------------------------------------------------
+
+a =\
+as.o xrealloc.o xmalloc.o hash.o hex-value.o \
+atof-generic.o append.o messages.o expr.o app.o \
+frags.o input-file.o input-scrub.o output-file.o \
+subsegs.o symbols.o version.o \
+flonum-const.o flonum-copy.o flonum-mult.o strstr.o bignum-copy.o \
+obstack.o
+#gdb.o gdb-file.o gdb-symbols.o gdb-blocks.o gdb-lines.o
+
+a: $(DEFAULT_GAS)
+ @rm -f a
+ @ln $(DEFAULT_GAS) a
+
+# I860 GAS ------------------------------------------------------------------
+u = i860.o atof-ieee.o write-i860.o read-i860.o
+
+U = i860.c i860.h i860-opcode.h
+
+i860.o: i860.c i860.h i860-opcode.h as.h frags.h struc-symbol.h
+i860.o: flonum.h expr.h hash.h md.h write.h read.h symbols.h
+ $(CC) -c $(CFLAGS) -DI860 i860.c
+
+atof-ieee.o: flonum.h
+
+write-i860.o: write.c i860.h
+ $(CC) -c -DI860 $(CFLAGS) write.c
+ mv write.o write-i860.o
+
+read-i860.o: read.c i860.h
+ $(CC) -c -DI860 $(CFLAGS) read.c
+ mv read.o read-i860.o
+
+a860: $a $u
+ $(CC) -o a860 $(LDFLAGS) $a $u $(LOADLIBES)
+
+# SPARC GAS ------------------------------------------------------------------
+v = sparc.o atof-ieee.o write-sparc.o read-sparc.o
+
+V = sparc.c sparc.h sparc-opcode.h
+
+atof-ieee.o: flonum.h
+sparc.o: sparc.c sparc.h sparc-opcode.h as.h frags.h struc-symbol.h
+sparc.o: flonum.h expr.h hash.h md.h write.h read.h symbols.h
+ $(CC) -c $(CFLAGS) -DSPARC sparc.c
+
+write-sparc.o: write.c
+ $(CC) -c -DSPARC $(CFLAGS) write.c
+ mv write.o write-sparc.o
+
+read-sparc.o: read.c
+ $(CC) -c -DSPARC $(CFLAGS) read.c
+ mv read.o read-sparc.o
+
+asparc: $a $v
+ $(CC) -o asparc $(LDFLAGS) $a $v $(LOADLIBES)
+
+# NS32K GAS ------------------------------------------------------------------
+w = ns32k.o atof-ieee.o write-ns32k.o read-ns32k.o
+
+W = ns32k.c ns32k-opcode.h
+
+atof-ieee.o: flonum.h
+ns32k.o: as.h frags.h struc-symbol.h flonum.h expr.h md.h hash.h
+ns32k.o: write.h symbols.h ns32k-opcode.h ns32k.c
+ $(CC) $(CFLAGS) $(OPTIONS) -c ns32k.c
+
+write-ns32k.o: write.c
+ $(CC) -c -DNS32K $(CFLAGS) write.c
+ mv write.o write-ns32k.o
+
+read-ns32k.o:
+ $(CC) -c -DNS32K $(CFLAGS) read.c
+ mv read.o read-ns32k.o
+
+a32k: $a $w
+ $(CC) -o a32k $(LDFLAGS) $a $w $(LOADLIBES)
+
+# 80386 GAS ------------------------------------------------------------------
+x = i386.o atof-ieee.o write.o read.o
+
+X = i386.c i386.h i386-opcode.h
+
+i386.o: i386.c as.h read.h flonum.h frags.h struc-symbol.h expr.h
+i386.o: symbols.h hash.h md.h i386.h i386-opcode.h
+ $(CC) $(CFLAGS) $(OPTIONS) -c i386.c
+
+atof-ieee.o: flonum.h
+
+a386: $a $x
+ $(CC) -o a386 $(LDFLAGS) $a $x $(LOADLIBES)
+
+# 68020 GAS ------------------------------------------------------------------
+y = m68k.o atof-ieee.o write.o read.o
+
+Y = m68k.c atof-ieee.c m68k-opcode.h m-hpux.h m-sun3.h m-generic.h
+
+atof-ieee.o: flonum.h
+
+m68k.o: m68k.c a.out.gnu.h as.h expr.h flonum.h frags.h hash.h
+m68k.o: m68k-opcode.h m68k.h md.h obstack.h struc-symbol.h
+ $(CC) $(CFLAGS) $(OPTIONS) -c m68k.c
+
+a68: $a $y
+ $(CC) -o a68 $(LDFLAGS) $a $y $(LOADLIBES)
+
+# VAX GAS --------------------------------------------------------------------
+z = vax.o atof-vax.o write.o read.o
+
+Z = vax.c atof-vax.c vax-opcode.h vax-inst.h \
+ make-gas.com objrecdef.h vms.c vms-dbg.c README-vms-dbg
+
+vax.o: vax.c a.out.gnu.h as.h expr.h flonum.h frags.h md.h obstack.h
+vax.o: read.h struc-symbol.h symbols.h vax-inst.h vax-opcode.h
+atof-vax.o: as.h flonum.h read.h
+
+avax: $a $z
+ $(CC) -o avax $(LDFLAGS) $a $z $(LOADLIBES)
+
+# global files ---------------------------------------------------------------
+
+as.o: as.c
+ $(CC) $(CFLAGS) $(OPTIONS) -c as.c
+
+messages.o: messages.c
+ $(CC) $(CFLAGS) $(OPTIONS) -c messages.c
+
+hash.o: hash.c
+ $(CC) $(CFLAGS) -Derror=as_fatal -c hash.c
+
+xmalloc.o: xmalloc.c
+ $(CC) $(CFLAGS) -Derror=as_fatal -c xmalloc.c
+
+xrealloc.o: xrealloc.c
+ $(CC) $(CFLAGS) -Derror=as_fatal -c xrealloc.c
+
+A =\
+as.c xrealloc.c xmalloc.c hash.c hex-value.c \
+atof-generic.c append.c messages.c expr.c bignum-copy.c \
+frags.c input-file.c input-scrub.c output-file.c read.c \
+subsegs.c symbols.c write.c strstr.c \
+flonum-const.c flonum-copy.c flonum-mult.c app.c version.c \
+obstack.c \
+#gdb.c gdb-file.c gdb-symbols.c gdb-blocks.c \
+#gdb-lines.c
+
+H = \
+a.out.gnu.h as.h bignum.h expr.h flonum.h \
+frags.h hash.h input-file.h md.h \
+obstack.h read.h struc-symbol.h subsegs.h \
+symbols.h write.h
+
+dist: COPYING README ChangeLog $A $H $Z $Y $X $W $V $U Makefile
+ echo gas-`sed -n -e '/ version /s/[^0-9.]*\([0-9.]*\).*/\1/p' < version.c` > .fname
+ mkdir `cat .fname`
+
+ ln COPYING README ChangeLog $A $H $Z $Y $X $W $V $U Makefile `cat .fname`
+ tar cvhZf `cat .fname`.tar.Z `cat .fname`
+ -rm -r `cat .fname`
+ -rm .fname
+
+clean:
+ rm -f a avax a68 a386 a32k asparc $a $v $w $x $y $z a core gmon.out bugs a.out
+
+install: a
+ cp a $(BINDIR)/gas
+
+
+# General .o-->.h dependencies
+
+app.o: as.h
+as.o: a.out.gnu.h as.h read.h struc-symbol.h write.h
+atof-generic.o: flonum.h
+bignum-copy.o: bignum.h
+expr.o: a.out.gnu.h as.h expr.h flonum.h obstack.h read.h struc-symbol.h
+expr.o: symbols.h
+flonum-const.o: flonum.h
+flonum-copy.o: flonum.h
+flonum-mult.o: flonum.h
+flonum-normal.o:flonum.h
+flonum-print.o: flonum.h
+frags.o: a.out.gnu.h as.h frags.h obstack.h struc-symbol.h subsegs.h
+#gdb.o: as.h
+#gdb-blocks.o: as.h
+#gdb-lines.o: as.h frags.h obstack.h
+#gdb-symbols.o: a.out.gnu.h as.h struc-symbol.h
+hash.o: hash.h
+input-file.o: input-file.h
+input-scrub.o: as.h input-file.h read.h
+messages.o: as.h
+obstack.o: obstack.h
+read.o: a.out.gnu.h as.h expr.h flonum.h frags.h hash.h md.h obstack.h
+read.o: read.h struc-symbol.h symbols.h
+subsegs.o: a.out.gnu.h as.h frags.h obstack.h struc-symbol.h subsegs.h write.h
+symbols.o: a.out.gnu.h as.h frags.h hash.h obstack.h struc-symbol.h symbols.h
+write.o: a.out.gnu.h as.h md.h obstack.h struc-symbol.h subsegs.h
+write.o: symbols.h write.h
+
+flonum.h: bignum.h
+
diff --git a/gnu/usr.bin/as/Makefile.in b/gnu/usr.bin/as/Makefile.in
new file mode 100644
index 0000000..1497b1f
--- /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.gnu b/gnu/usr.bin/as/README.gnu
new file mode 100644
index 0000000..46f135fc
--- /dev/null
+++ b/gnu/usr.bin/as/README.gnu
@@ -0,0 +1,133 @@
+This is the beta-test version of the GNU assembler. (Probably
+around Version 1.35, but check version.c which gets updated more
+often than this readme.)
+
+The assembler has been modified to support a feature that is
+potentially useful when assembling compiler output, but which may
+confuse assembly language programmers. If assembler encounters a
+.word pseudo-op of the form symbol1-symbol2 (the difference of two
+symbols), and the difference of those two symbols will not fit in 16
+bits, the assembler will create a branch around a long jump to
+symbol1, and insert this into the output directly before the next
+label: The .word will (instead of containing garbage, or giving an
+error message) contain (the address of the long jump)-symbol2. This
+allows the assembler to assemble jump tables that jump to locations
+very far away into code that works properly. If the next label is
+more than 32K away from the .word, you lose (silently) RMS claims
+this will never happen. If the -k option is given, you will get a
+warning message when this happens.
+
+These files are currently set up to allow you to compile all of the
+versions of the assembler (68020, VAX, ns32k, and i386) on the same
+machine. To compile the 68020 version, type 'make a68'. To compile
+the VAX version, type 'make avax'. To compile the ns32k version,
+type 'make a32k'. To compile the Intel 80386 version, type 'make
+a386'. The Makefile contains instructions on how to make one of the
+assemblers compile as the default.
+
+Before you can compile the 68020 version of the assembler, you must
+make m68k.h be a link to m-sun3.h , m-hpux.h or m-generic.h . If
+you are on a SUN-3 (or other machine that uses a magic number of
+(2 << 16) | OMAGIC type 'ln -s m-sun3.h m68k.h' else if you are on a
+machine running HP-UX, type 'ln m-hpux.h m689k.h' else type
+'ln -s m-generic.h m68k.h' If your machine does not support symbolic
+links, omit the '-s'.
+
+See the instructions in the Makefile for compiling gas for the Sequent
+Symmetry (dynix 3.0.12 + others?) or for the HP 9000/300
+
+If your machine does not have both varargs.h and vfprintf(), but does have
+_doprnt() add -DNO_VARARGS to the CFLAGS line in the makefile. If your
+machine has neither vfprintf() or _doprnt(), you will have to change
+messages.c in order to get readable error messages from the assembler.
+
+
+ REPORTING BUGS IN GAS
+
+Bugs in gas should be reported to bug-gnu-utils@prep.ai.mit.edu If you can't
+get through to prep, try hack@gnu.ai.mit.edu or hack@media-lab.media.mit.edu
+
+If you report a bug in GAS, please remember to include:
+
+A description of exactly what went wrong.
+
+The type of machine GAS was running on (VAX, 68020, etc),
+
+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.
+
+------------------------------ README.APOLLO ---------------------------------
+
+The changes required to get the GNU C compiler running on
+Apollo 68K platforms are available via anonymous ftp from
+labrea.stanford.edu (36.8.0.47) in the form of a compressed
+tar file named "/pub/gnu/apollo-gcc-1.37.tar.Z".
+The size of the file is 84145 bytes.
+
+To build GCC for the Apollo you'll need the virgin FSF
+distributions of bison-1.03, gas-1.34, and gcc-1.37. They
+are also on labrea.stanford.edu as well as prep.ai.mit.edu.
+My changes are to enable gas to produce Apollo COFF object
+files and allow gcc to parse some of the syntax extensions
+which appear in Apollo C header files. Note that the
+COFF encapsulation technique cannot be used on the Apollo.
+
+The tar file should be unpacked in the directory containing
+the gas-1.34 and gcc-1.37 directories; a few files will be overlaid,
+and an APOLLO-GCC-README file will appear in the top directory.
+This file contains detailed instructions on how to proceed.
+
+These changes will only work for SR10.1 or later systems, using
+the 6.6 or later version of the Apollo C compiler.
+
+If you do not have ftp access, I can mail you the changes in the
+form of diffs; they are approximately 40K in length. If you request
+them, be sure to give me a voice phone number so I can contact you
+in case I can't send you mail; I've had several requests in the
+past from people I can't contact.
+
+By the way, I'm working on getting the GNU C++ compiler running;
+there are a couple problems to solve. I hope to be able to announce
+the Apollo version shortly after the 1.37 version is released.
+
+John Vasta Hewlett-Packard Apollo Systems Division
+vasta@apollo.hp.com M.S. CHA-01-LT
+(508) 256-6600 x6362 300 Apollo Drive, Chelmsford, MA 01824
+UUCP: {decwrl!decvax, mit-eddie, attunix}!apollo!vasta
+
+------------------------------------
+
+You might refer others who are interested in a similar thing.
+
+Kevin Buchs buchs@mayo.edu
+
+
+------------------------------ README.COFF -----------------------------------
+
+If you have a COFF system, you may wish to aquire
+
+ UUCP: osu-cis!~/gnu/coff/gnu-coff.tar.Z
+ or
+ FTP: tut.cis.ohio-state.edu:/pub/gnu/coff/gnu-coff.tar.Z
+
+These contain patches for gas that will make it produce COFF output.
+I have never seen these patches, so I don't know how well they work.
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..4c89a77
--- /dev/null
+++ b/gnu/usr.bin/as/app.c
@@ -0,0 +1,539 @@
+/* Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ Modified by Allen Wirfs-Brock, Instantiations Inc 2/90
+ */
+/* This is the Assembler Pre-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 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. */
+
+/* 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.app-file <filename> pair.
+ This needs better error-handling.
+ */
+#ifndef lint
+static char rcsid[] = "$Id: app.c,v 1.3 1993/10/02 20:57:12 pk Exp $";
+#endif
+
+#include <stdio.h>
+#include "as.h" /* For BAD_CASE() only */
+
+#if (__STDC__ != 1) && !defined(const)
+#define const /* Nothing */
+#endif
+
+static char lex[256];
+static char symbol_chars[] =
+ "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+/* These will go in BSS if not defined elsewhere, producing empty strings. */
+extern const char comment_chars[];
+extern const char line_comment_chars[];
+extern const char line_separator_chars[];
+
+#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)
+
+/* 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;
+ lex['\''] = LEX_IS_ONECHAR_QUOTE;
+ lex[':'] = LEX_IS_COLON;
+
+ /* 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[*p] = LEX_IS_SYMBOL_COMPONENT;
+ } /* declare symbol characters */
+
+ for (p = line_comment_chars; *p; p++) {
+ lex[*p] = LEX_IS_LINE_COMMENT_START;
+ } /* declare line comment chars */
+
+ for (p = comment_chars; *p; p++) {
+ lex[*p] = LEX_IS_COMMENT_START;
+ } /* declare comment chars */
+
+ for (p = line_separator_chars; *p; p++) {
+ lex[*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(out_buf, saved->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(saved->out_buf, 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() */
+
+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 .app-file, put out string.
+ 8: After putting out a .app-file string, flush until newline.
+ -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
+ */
+
+ register int ch, ch2 = 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.app-file ";
+ old_state=7;
+ state= -1;
+ return *out_string++;
+ } else {
+ while (ch != EOF && ch != '\n')
+ ch=(*get)();
+ return ch;
+ }
+ }
+
+ case 5:
+ ch=(*get)();
+ if (ch == '"') {
+ state=old_state;
+ return '"';
+ } else if (ch == '\\') {
+ state=6;
+ return ch;
+ } 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) {
+ /* This is neet. Turn "string
+ more string" into "string\n more string"
+ */
+ 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 '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ break;
+
+#ifdef 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 */
+
+ /* 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 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)) {
+ goto recycle;
+ }
+ switch (state) {
+ case 0: state++; goto recycle; /* Punted leading sp */
+ case 1: BAD_CASE(state); /* We can't get here */
+ case 2: state++; (*unget)(ch); return ' '; /* Sp after opco */
+ case 3: goto recycle; /* Sp in operands */
+ 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);
+ return ch;
+ }
+ break;
+
+ case LEX_IS_STRINGQUOTE:
+ old_state=state;
+ state=5;
+ return ch;
+
+#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;
+ }
+ 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
+ }
+
+ old_state=state;
+ state= -1;
+ out_string=out_buf;
+ return *out_string++;
+#endif
+ case LEX_IS_COLON:
+ if (state != 3)
+ state=0;
+ 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) /* Not at start of line, act normal */
+ goto de_fault;
+
+ /* 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)()) == '*') {
+ state = -2;
+ return(do_scrub_next_char(get, unget));
+ } else {
+ (*unget)(ch2);
+ } /* bad hack */
+
+ 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') {
+ /* 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=".line ";
+ return *out_string++;
+
+ 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';
+
+ default:
+ de_fault:
+ /* Some relatively `normal' character. */
+ if (state == 0) {
+ state=2; /* Now seeing opcode */
+ return ch;
+ } else if (state == 1) {
+ state=2; /* Ditto */
+ return ch;
+ } else {
+ return ch; /* Opcode or operands already */
+ }
+ }
+ return -1;
+}
+
+#ifdef TEST
+
+char comment_chars[] = "|";
+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
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of app.c */
diff --git a/gnu/usr.bin/as/append.c b/gnu/usr.bin/as/append.c
new file mode 100644
index 0000000..d51a27f
--- /dev/null
+++ b/gnu/usr.bin/as/append.c
@@ -0,0 +1,37 @@
+/* Append a string ontp another string
+ 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. */
+
+/* JF: This is silly. Why not stuff this in some other file? */
+#ifdef USG
+#define bcopy(from,to,n) memcpy(to,from,n)
+#endif
+
+void
+append (charPP, fromP, length)
+char **charPP;
+char *fromP;
+unsigned long length;
+{
+ if (length) { /* Don't trust bcopy() of 0 chars. */
+ bcopy (fromP, * charPP,(int) length);
+ *charPP += length;
+ }
+}
+
+/* end: append.c */
diff --git a/gnu/usr.bin/as/as.1 b/gnu/usr.bin/as/as.1
new file mode 100644
index 0000000..57e2dc1
--- /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
+GNU 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..57e2dc1
--- /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
+GNU 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..a9cbb70
--- /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.3 1993/10/02 20:57:15 pk 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..7b1e27d
--- /dev/null
+++ b/gnu/usr.bin/as/as.h
@@ -0,0 +1,416 @@
+/* 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 1993/10/02 20:57:16 pk 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__ */
+
+/*
+ * 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(char *gripe, char *filename);
+void as_where(void);
+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..b4e0971
--- /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.3 1993/10/02 20:57:17 pk 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..08c92f8
--- /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.3 1993/10/02 20:57:18 pk 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..d95ca9a
--- /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.3 1993/10/02 20:57:19 pk 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..e72d6d6
--- /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/10/02 20:57:19 pk 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..ad98201
--- /dev/null
+++ b/gnu/usr.bin/as/cond.c
@@ -0,0 +1,239 @@
+/* cond.c - conditional assembly pseudo-ops, and .include
+ Copyright (C) 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: cond.c,v 1.1 1993/10/02 20:57:20 pk 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 *logical_file;
+ int logical_line;
+ char *physical_file;
+ int physical_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 */
+
+#if __STDC__ == 1
+
+static void get_file_line(struct file_line *into);
+static void initialize_cframe(struct conditional_frame *cframe);
+static void set_file_line(struct file_line *from);
+
+#else
+
+static void get_file_line();
+static void initialize_cframe();
+static void set_file_line();
+
+#endif
+
+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. */
+ expr(0, &operand);
+
+ if (operand.X_add_symbol != NULL
+ || operand.X_subtract_symbol != NULL) {
+ as_bad("non-constant expression in \".if\" statement");
+ } /* bad condition */
+
+ /* 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) {
+ struct file_line hold;
+ as_bad("duplicate \"else\" - ignored");
+
+ get_file_line(&hold);
+ set_file_line(&current_cframe->else_file_line);
+ as_bad("here is the previous \"else\".");
+ set_file_line(&current_cframe->if_file_line);
+ as_bad("here is the matching \".if\".");
+ set_file_line(&hold);
+
+ } else {
+ get_file_line(&current_cframe->else_file_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() {
+ char *ptr = obstack_next_free (&cond_obstack);
+
+ /* 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));
+ get_file_line(&(cframe->if_file_line));
+ cframe->previous_cframe = current_cframe;
+ cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring;
+
+ return;
+} /* initialize_cframe() */
+
+static void get_file_line(into)
+struct file_line *into;
+{
+ extern char *logical_input_file;
+ extern char *physical_input_file;
+ extern int logical_input_line;
+ extern int physical_input_line;
+
+ into->logical_file = logical_input_file;
+ into->logical_line = logical_input_line;
+ into->physical_file = physical_input_file;
+ into->physical_line = physical_input_line;
+
+ return;
+} /* get_file_line() */
+
+static void set_file_line(from)
+struct file_line *from;
+{
+ extern char *logical_input_file;
+ extern char *physical_input_file;
+ extern int logical_input_line;
+ extern int physical_input_line;
+
+ logical_input_file = from->logical_file;
+ logical_input_line = from->logical_line;
+ physical_input_file = from->physical_file;
+ physical_input_line = from->physical_line;
+ return;
+} /* set_file_line() */
+
+/*
+ * 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..bbae017
--- /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.3 1993/10/02 20:58:21 pk Exp $
+
+CFLAGS+= -DNON_BROKEN_WORDS
+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..c9d9af1
--- /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/10/02 20:58:22 pk Exp $
+
+CFLAGS+= -DNON_BROKEN_WORDS
+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/a.out.gnu.h b/gnu/usr.bin/as/config/a.out.gnu.h
new file mode 100644
index 0000000..71b09a0
--- /dev/null
+++ b/gnu/usr.bin/as/config/a.out.gnu.h
@@ -0,0 +1,261 @@
+#ifndef __A_OUT_GNU_H__
+#define __A_OUT_GNU_H__
+
+#define __GNU_EXEC_MACROS__
+
+#ifndef __STRUCT_EXEC_OVERRIDE__
+
+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 */
+enum machine_type {
+#if defined (M_OLDSUN2)
+ M__OLDSUN2 = M_OLDSUN2,
+#else
+ M_OLDSUN2 = 0,
+#endif
+#if defined (M_68010)
+ M__68010 = M_68010,
+#else
+ M_68010 = 1,
+#endif
+#if defined (M_68020)
+ M__68020 = M_68020,
+#else
+ M_68020 = 2,
+#endif
+#if defined (M_SPARC)
+ M__SPARC = M_SPARC,
+#else
+ M_SPARC = 3,
+#endif
+ /* skip a bunch so we don't run into any of sun's numbers */
+ M_386 = 100,
+};
+
+#if !defined (N_MAGIC)
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#endif
+#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
+
+#if !defined (N_BADMAG)
+#define N_BADMAG(x) \
+ (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC)
+#endif
+
+#define _N_BADMAG(x) \
+ (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC)
+
+#define _N_HDROFF(x) (1024 - sizeof (struct exec))
+
+#if !defined (N_TXTOFF)
+#define N_TXTOFF(x) \
+ (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec))
+#endif
+
+#if !defined (N_DATOFF)
+#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
+#endif
+
+#if !defined (N_TRELOFF)
+#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data)
+#endif
+
+#if !defined (N_DRELOFF)
+#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize)
+#endif
+
+#if !defined (N_SYMOFF)
+#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize)
+#endif
+
+#if !defined (N_STROFF)
+#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms)
+#endif
+
+/* Address of text segment in memory after it is loaded. */
+#if !defined (N_TXTADDR)
+#define N_TXTADDR(x) 0
+#endif
+
+/* Address of data segment in memory after it is loaded.
+ Note that it is up to you to define SEGMENT_SIZE
+ on machines not listed here. */
+#if defined(vax) || defined(hp300) || defined(pyr)
+#define SEGMENT_SIZE page_size
+#endif
+#ifdef sony
+#define SEGMENT_SIZE 0x2000
+#endif /* Sony. */
+#ifdef is68k
+#define SEGMENT_SIZE 0x20000
+#endif
+#if defined(m68k) && defined(PORTAR)
+#define PAGE_SIZE 0x400
+#define SEGMENT_SIZE PAGE_SIZE
+#endif
+
+#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1))
+
+#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
+
+#ifndef N_DATADDR
+#define N_DATADDR(x) \
+ (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
+ : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
+#endif
+
+/* Address of bss segment in memory after it is loaded. */
+#if !defined (N_BSSADDR)
+#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
+#endif
+
+#if !defined (N_NLIST_DECLARED)
+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;
+};
+#endif /* no N_NLIST_DECLARED. */
+
+#if !defined (N_UNDF)
+#define N_UNDF 0
+#endif
+#if !defined (N_ABS)
+#define N_ABS 2
+#endif
+#if !defined (N_TEXT)
+#define N_TEXT 4
+#endif
+#if !defined (N_DATA)
+#define N_DATA 6
+#endif
+#if !defined (N_BSS)
+#define N_BSS 8
+#endif
+#if !defined (N_FN)
+#define N_FN 15
+#endif
+
+#if !defined (N_EXT)
+#define N_EXT 1
+#endif
+#if !defined (N_TYPE)
+#define N_TYPE 036
+#endif
+#if !defined (N_STAB)
+#define N_STAB 0340
+#endif
+
+/* 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 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. */
+
+#if !defined (N_RELOCATION_INFO_DECLARED)
+/* 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 relocation_info
+{
+ /* Address (within segment) to be relocated. */
+ int r_address;
+ /* 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 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;
+ /* Four bits that aren't used, but when writing an object file
+ it is desirable to clear them. */
+#ifdef NS32K
+ unsigned r_bsr:1;
+ unsigned r_disp:1;
+ unsigned r_pad:2;
+#else
+ unsigned int r_pad:4;
+#endif
+};
+#endif /* no N_RELOCATION_INFO_DECLARED. */
+
+
+#endif /* __A_OUT_GNU_H__ */
diff --git a/gnu/usr.bin/as/config/aout.h b/gnu/usr.bin/as/config/aout.h
new file mode 100644
index 0000000..23b085a
--- /dev/null
+++ b/gnu/usr.bin/as/config/aout.h
@@ -0,0 +1,430 @@
+/* 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. */
+ 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 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;
+ /* 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 */
+
+#ifdef TC_NS32K
+#define r_bsr r_baserel
+#define r_disp r_jmptable
+#endif /* TC_NS32K */
+
+ unsigned int r_relative:1; /* "relative relocation" */
+ /* unused */
+ unsigned int r_pad:1; /* Padding -- set to zero */
+};
+#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..18941cc
--- /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.3 1993/10/02 20:58:25 pk 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..6425e93
--- /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..8a69502
--- /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..bcbb343
--- /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..e3819bc
--- /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..2af0341
--- /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..1cab4d5
--- /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..493cfc6
--- /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..d5ff31a
--- /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..6941b7e
--- /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/10/02 20:58:36 pk 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..d31b51a
--- /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..fe57e8e
--- /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..1193b1b
--- /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..443fe3b
--- /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..eee0553
--- /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..4b6680e
--- /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/i386-opcode.h b/gnu/usr.bin/as/config/i386-opcode.h
new file mode 100644
index 0000000..cace0c3
--- /dev/null
+++ b/gnu/usr.bin/as/config/i386-opcode.h
@@ -0,0 +1,806 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ *
+ * @(#)i386-opcode.h 6.3 (Berkeley) 5/8/91
+ */
+
+/* i386-opcode.h -- Intel 80386 opcode table
+ Copyright (C) 1989, 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. */
+
+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 },
+
+/* 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, Imm32, 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},
+
+{"setb", 1, 0x0f92, 0, Modrm, Reg8|Mem, 0, 0},
+{"setnae", 1, 0x0f92, 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},
+{"ins", 0, 0x6c, _, W|NoModrm, 0, 0, 0},
+{"outs", 0, 0x6e, _, W|NoModrm, 0, 0, 0},
+{"lods", 0, 0xac, _, W|NoModrm, 0, 0, 0},
+{"movs", 0, 0xa4, _, W|NoModrm, 0, 0, 0},
+{"scas", 0, 0xae, _, W|NoModrm, 0, 0, 0},
+{"stos", 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, 0xdac0, _, 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, 0xdae0, _, ShortForm, FloatReg, 0, 0},
+{"fsubp", 2, 0xdae0, _, 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, 0xdae8, _, ShortForm, FloatReg, 0, 0},
+{"fsubrp", 2, 0xdae8, _, 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, 0xdac8, _, ShortForm, FloatReg, 0, 0},
+{"fmulp", 2, 0xdac8, _, 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, 0xdaf0, _, ShortForm, FloatReg, 0, 0},
+{"fdivp", 2, 0xdaf0, _, 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, 0xdaf8, _, ShortForm, FloatReg, 0, 0},
+{"fdivrp", 2, 0xdaf8, _, 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},
+{"word", 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},
+
+{"", 0, 0, 0, 0, 0, 0, 0} /* sentinal */
+};
+#undef _
+
+template *i386_optab_end
+ = i386_optab + sizeof (i386_optab)/sizeof(i386_optab[0]);
+
+/* 386 register table */
+
+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 */
+
+reg_entry *i386_regtab_end
+ = i386_regtab + sizeof(i386_regtab)/sizeof(i386_regtab[0]);
+
+/* segment stuff */
+seg_entry cs = { "cs", 0x2e };
+seg_entry ds = { "ds", 0x3e };
+seg_entry ss = { "ss", 0x36 };
+seg_entry es = { "es", 0x26 };
+seg_entry fs = { "fs", 0x64 };
+seg_entry gs = { "gs", 0x65 };
+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;
+*/
+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 */
+};
+
+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 */
+};
+
+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 }, /* repeat string instructions */
+ { "repne", 0xf2 }
+};
+
+prefix_entry *i386_prefixtab_end
+ = i386_prefixtab + sizeof(i386_prefixtab)/sizeof(i386_prefixtab[0]);
+
diff --git a/gnu/usr.bin/as/config/i386.c b/gnu/usr.bin/as/config/i386.c
new file mode 100644
index 0000000..2281acd
--- /dev/null
+++ b/gnu/usr.bin/as/config/i386.c
@@ -0,0 +1,1946 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)i386.c 6.4 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* i386.c -- Assemble code for the Intel 80386
+ Copyright (C) 1989, 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. */
+
+/*
+ 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.
+*/
+
+#include <stdio.h>
+#include <varargs.h>
+#include <ctype.h>
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+extern char *alloca();
+#endif
+#ifdef USG
+#define index strchr
+#endif
+
+#include "as.h"
+#include "read.h"
+#include "flonum.h"
+#include "obstack.h"
+#include "frags.h"
+#include "struc-symbol.h"
+#include "expr.h"
+#include "symbols.h"
+#include "hash.h"
+#include "md.h"
+#include "i386.h"
+#include "i386-opcode.h"
+
+long omagic = OMAGIC;
+char FLT_CHARS[] = "fFdDxX";
+char EXP_CHARS[] = "eE";
+char line_comment_chars[] = "#";
+char comment_chars[] = "#";
+
+/* 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},
+
+};
+
+void float_cons (), cons ();
+
+/* 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[] = {
+ { "ffloat", float_cons, 'f' },
+ { "dfloat", float_cons, 'd' },
+ { "tfloat", float_cons, 'x' },
+ { "value", cons, 2 },
+ { "ident", dummy, 0 }, /* ignore these directives */
+ { "def", dummy, 0 },
+ { "optim", dummy, 0 }, /* For sun386i cc */
+ { "version", dummy, 0 },
+ { "ln", dummy, 0 },
+ { 0, 0, 0 }
+};
+
+/* for interface with expression () */
+extern char * input_line_pointer;
+char * index ();
+
+char * output_invalid ();
+reg_entry * parse_register ();
+
+/* 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 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 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 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;
+
+ bzero (opcode_chars, sizeof(opcode_chars));
+ bzero (operand_chars, sizeof(operand_chars));
+ bzero (space_chars, sizeof(space_chars));
+ bzero (identifier_chars, sizeof(identifier_chars));
+ bzero (digit_chars, 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 && index(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. */
+
+
+#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");
+ }
+}
+
+char *seg_names[] = {
+"SEG_ABSOLUTE", "SEG_TEXT", "SEG_DATA", "SEG_BSS", "SEG_UNKNOWN",
+"SEG_NONE", "SEG_PASS1", "SEG_GOOF", "SEG_BIG", "SEG_DIFFERENCE" };
+
+static void pe (e)
+ expressionS *e;
+{
+ fprintf (stdout, " segment %s\n", seg_names[(int) 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");
+ }
+}
+
+#define SYMBOL_TYPE(t) \
+ (((t&N_TYPE) == N_UNDF) ? "UNDEFINED" : \
+ (((t&N_TYPE) == N_ABS) ? "ABSOLUTE" : \
+ (((t&N_TYPE) == N_TEXT) ? "TEXT" : \
+ (((t&N_TYPE) == N_DATA) ? "DATA" : \
+ (((t&N_TYPE) == N_BSS) ? "BSS" : "Bad n_type!")))))
+
+static void ps (s)
+ symbolS *s;
+{
+ fprintf (stdout, "%s type %s%s",
+ s->sy_nlist.n_un.n_name,
+ (s->sy_nlist.n_type&N_EXT) ? "EXTERNAL " : "",
+ SYMBOL_TYPE (s->sy_nlist.n_type));
+}
+
+struct type_name {
+ uint 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)
+ uint 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. */
+ bzero (&i, sizeof(i));
+ bzero (disp_expressions, sizeof(disp_expressions));
+ bzero (im_expressions, 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. */
+
+ /* TRUE if operand is pending after ','. */
+ uint expecting_operand = 0;
+ /* TRUE if we found a prefix only acceptable with string insns. */
+ uint expecting_string_instruction = 0;
+ /* Non-zero if operand parens not balenced. */
+ uint 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 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 = TRUE;
+ /* 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)) {
+ 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 */
+ uint 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 = TRUE;
+ }
+ } 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 uint overlap0, overlap1;
+ expressionS * exp;
+ uint overlap2;
+ uint 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!). */
+ bcopy (t, &i.tm, 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) {
+ uint 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) {
+ uint first_reg_operand = (i.types[0] & Reg) ? 0 : 1;
+ uint 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. */
+ uint 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) {
+ uint 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) {
+ uint fake_zero_displacement = FALSE;
+ uint 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 = TRUE;
+ /* 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 = TRUE; /* 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 = TRUE;
+ 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) {
+ uint seg_index;
+ 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) {
+ uint 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,
+ ((uchar) *p == JUMP_PC_RELATIVE
+ ? ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE)
+ : ENCODE_RELAX_STATE (COND_JUMP, BYTE)),
+ i.disps[0]->X_add_symbol,
+ n, p);
+ 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);
+ 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);
+ 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. */
+ register char *q;
+
+ /* First the prefix bytes. */
+ for (q = i.prefix; q < i.prefix + i.prefixes; q++) {
+ p = frag_more (1);
+ md_number_to_chars (p, (uint) *q, 1);
+ }
+
+ /* Now the opcode; be careful about word order here! */
+ if (FITS_IN_UNSIGNED_BYTE(t->base_opcode)) {
+ FRAG_APPEND_1_CHAR (t->base_opcode);
+ } else if (FITS_IN_UNSIGNED_WORD(t->base_opcode)) {
+ p = frag_more (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);
+ *p++ = (t->base_opcode >> 24) & 0xff;
+ } else p = frag_more (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);
+ /* 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);
+ /* 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 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) */
+ p = frag_more (4);
+ 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);
+ }
+ }
+ }
+ } /* end displacement output */
+
+ /* output immediate */
+ if (i.imm_operands) {
+ register 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 ... */
+ 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);
+ 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);
+ }
+ }
+ }
+ } /* 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. */
+
+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 = 0;
+ char * displacement_string_end;
+
+ /* 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 = &es; break;
+ case 1:
+ i.seg = &cs; break;
+ case 2:
+ i.seg = &ss; break;
+ case 3:
+ i.seg = &ds; break;
+ case 4:
+ i.seg = &fs; break;
+ case 5:
+ i.seg = &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;
+ register expressionS *exp;
+ segT exp_seg;
+ 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;
+ input_line_pointer = ++op_string; /* must advance op_string! */
+ exp_seg = expression (exp);
+ input_line_pointer = save_input_line_pointer;
+ switch (exp_seg) {
+ case SEG_NONE: /* 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:
+ 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;
+ uint 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 = FALSE;
+ if (*base_string == ')') {
+ uint 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 = TRUE;
+ }
+
+ /* 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;
+ char * save_input_line_pointer;
+ exp = &disp_expressions[i.disp_operands];
+ i.disps [this_operand] = exp;
+ i.disp_operands++;
+ save_input_line_pointer = input_line_pointer;
+ input_line_pointer = displacement_string_start;
+ END_STRING_AND_SAVE (displacement_string_end);
+ exp_seg = expression (exp);
+ 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_NONE:
+ /* missing expr becomes absolute 0 */
+ as_bad ("missing or invalid displacement '%s' taken as 0",
+ operand_string);
+ 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;
+ break;
+ case SEG_ABSOLUTE:
+ i.types[this_operand] |= SMALLEST_DISP_TYPE (exp->X_add_number);
+ break;
+ case SEG_TEXT: case SEG_DATA: case SEG_BSS:
+ case SEG_UNKNOWN: /* must be 32 bit displacement (i.e. address) */
+ i.types[this_operand] |= Disp32;
+ 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;
+ }
+ 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_type)
+ register fragS * fragP;
+ register int segment_type; /* N_DATA or N_TEXT. */
+{
+ register uchar * opcode;
+ register int old_fr_fix;
+
+ old_fr_fix = fragP -> fr_fix;
+ opcode = (uchar *) fragP -> fr_opcode;
+ /* We've already got fragP->fr_subtype right; all we have to do is check
+ for un-relaxable symbols. */
+ if ((fragP -> fr_symbol -> sy_type & N_TYPE) != segment_type) {
+ /* 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);
+ 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);
+ 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 (fragP)
+ register fragS * fragP;
+{
+ register uchar * opcode;
+ uchar * where_to_put_displacement;
+ uint target_address, opcode_address;
+ uint extension;
+ int displacement_from_opcode_start;
+
+ opcode = (uchar *) fragP -> fr_opcode;
+
+ /* Address we want to reach in file space. */
+ target_address = fragP->fr_symbol->sy_value + 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 (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 */
+
+void md_create_short_jump(ptr, from_addr, to_addr)
+ char *ptr;
+ long from_addr, to_addr;
+{
+ 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 - to_symbol->sy_value;
+ 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 int) 0, 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;
+{
+ return 1;
+}
+
+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. */
+{
+ 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);
+ }
+}
+
+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. */
+{
+ char * answer = alloca (nbytes);
+ register char * p = answer;
+
+ switch (nbytes) {
+ 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 (nbytes);
+ }
+ bcopy (answer, con, nbytes);
+}
+
+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. */
+{
+ char * answer = alloca (nbytes);
+ register char * p = answer;
+
+ switch (nbytes) {
+ 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 (nbytes);
+ }
+ bcopy (answer, con, 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. */
+{
+ char * answer = alloca (nbytes);
+ register char * p = answer;
+
+ switch (nbytes) {
+ 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 (nbytes);
+ }
+ bcopy (answer, con, nbytes);
+}
+
+long int /* 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 int retval;
+ for (retval=0, con+=nbytes-1; nbytes--; con--)
+ {
+ retval <<= BITS_PER_CHAR;
+ retval |= *con;
+ }
+ return retval;
+}
+
+void md_ri_to_chars(ri_p, ri)
+ struct relocation_info *ri_p, ri;
+{
+ unsigned char the_bytes[8];
+
+ /* 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;
+ /* now put it back where you found it */
+ bcopy (the_bytes, (char *)ri_p, sizeof(struct relocation_info));
+}
+
+
+#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;
+ char *atof_ieee();
+
+ 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];
+
+char * output_invalid (c)
+ char c;
+{
+ if (isprint(c)) sprintf (output_invalid_buf, "'%c'", c);
+ else sprintf (output_invalid_buf, "(0x%x)", c);
+ return output_invalid_buf;
+}
+
+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);
+}
+
diff --git a/gnu/usr.bin/as/config/i386.h b/gnu/usr.bin/as/config/i386.h
new file mode 100644
index 0000000..c569c1c
--- /dev/null
+++ b/gnu/usr.bin/as/config/i386.h
@@ -0,0 +1,296 @@
+/* i386.h -- Header file for i386.c
+ Copyright (C) 1989, 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. */
+
+#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
+
+/* 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 MODE_FROM_DISP_SIZE(t) \
+ ((t&(Disp8)) ? 1 : \
+ ((t&(Disp32)) ? 2 : 0))
+
+#define Byte (Reg8|Imm8|Imm8S)
+#define Word (Reg16|Imm16)
+#define DWord (Reg32|Imm32)
+
+/* convert opcode suffix ('b' 'w' 'l' typically) into type specifyer */
+#define OPCODE_SUFFIX_TO_TYPE(s) \
+ (s == BYTE_OPCODE_SUFFIX ? Byte : \
+ (s == WORD_OPCODE_SUFFIX ? Word : DWord))
+
+#define FITS_IN_SIGNED_BYTE(num) ((num) >= -128 && (num) <= 127)
+#define FITS_IN_UNSIGNED_BYTE(num) ((num) >= 0 && (num) <= 255)
+#define FITS_IN_UNSIGNED_WORD(num) ((num) >= 0 && (num) <= 65535)
+#define FITS_IN_SIGNED_WORD(num) ((num) >= -32768 && (num) <= 32767)
+
+#define SMALLEST_DISP_TYPE(num) \
+ FITS_IN_SIGNED_BYTE(num) ? (Disp8|Disp32|Abs8|Abs32) : (Disp32|Abs32)
+
+#define SMALLEST_IMM_TYPE(num) \
+ (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)
+
+typedef unsigned char uchar;
+typedef unsigned int uint;
+
+typedef struct {
+ /* instruction name sans width suffix ("mov" for movl insns) */
+ char *name;
+
+ /* how many operands */
+ uint operands;
+
+ /* base_opcode is the fundamental opcode byte with a optional prefix(es). */
+ uint 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 */
+ uchar 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 */
+ uint 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 */
+ uint 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;
+ uint reg_type;
+ uint reg_num;
+} reg_entry;
+
+typedef struct {
+ char * seg_name;
+ uint seg_prefix;
+} seg_entry;
+
+/* these are for prefix name --> prefix code hash lookup */
+typedef struct {
+ char * prefix_name;
+ uchar 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;
+
+/* '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. */
+ uint operands;
+
+ /* REG_OPERANDS, DISP_OPERANDS, MEM_OPERANDS, IMM_OPERANDS give the number of
+ given register, displacement, memory operands and immediate operands. */
+ uint 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. */
+ uint types [MAX_OPERANDS];
+
+ /* Displacements (if given) for each operand. */
+ expressionS * disps [MAX_OPERANDS];
+
+ /* 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;
+ uint log2_scale_factor;
+
+ /* SEG gives the seg_entry of this insn. It is equal to zero unless
+ an explicit segment override is given. */
+ seg_entry * seg; /* segment for memory operands (if given) */
+
+ /* PREFIX holds all the given prefix opcodes (usually null).
+ PREFIXES is the size of PREFIX. */
+ char prefix [MAX_PREFIXES];
+ uint 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;
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..30eb2d1
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-aout.c
@@ -0,0 +1,648 @@
+/* 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"
+
+
+#ifndef NO_LISTING
+#include "aout/stab_gnu.h"
+#endif /* NO_LISTING */
+
+/* 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,
+};
+
+#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(OLD_GAS) && defined(TC_I386)
+ /* I think that this old behaviour was wrong, but this lets me compare to the
+ previous gas. xoxorich. */
+ md_number_to_chars(*where, headers->header.a_info, 2);
+ *where += 2;
+ md_number_to_chars(*where, 0, 2);
+ *where += 2;
+#else /* not (TC_I386 && OLD_GAS) */
+ md_number_to_chars(*where, headers->header.a_info, sizeof(headers->header.a_info));
+ *where += sizeof(headers->header.a_info);
+#endif /* not (TC_I386 && OLD_GAS) */
+
+#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_DYNAMIC(headers, 0);
+ H_SET_VERSION(headers, 0);
+ H_SET_MACHTYPE(headers, AOUT_MACHTYPE);
+
+ H_SET_MAGIC_NUMBER(headers, DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE);
+ 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..af3d9b0
--- /dev/null
+++ b/gnu/usr.bin/as/config/obj-aout.h
@@ -0,0 +1,210 @@
+/* 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.1 1993/11/03 00:53:50 paul 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 /* AOUT_MACHTYPE */
+
+extern const short seg_N_TYPE[];
+extern const segT N_TYPE_seg[];
+
+#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)
+
+#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_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..626516b
--- /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..958d8a9
--- /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..f6d9302
--- /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..e28d435
--- /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..238e6c5
--- /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..9720d5e
--- /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..d69c7a0
--- /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..d1afabb
--- /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..a91eff9
--- /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..f370722
--- /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..5f74a5f
--- /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..3baa081
--- /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..5d12387
--- /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..fec056d
--- /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..84ec97a
--- /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..fee1ca2
--- /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..181d4aa
--- /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..db4786b
--- /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..6da7896
--- /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..84848d2
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-i386.c
@@ -0,0 +1,2313 @@
+/* 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.1 1993/11/03 00:54:23 paul 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)) {
+ 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;
+
+ 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);
+ 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;
+ break;
+ case SEG_ABSOLUTE:
+ i.types[this_operand] |= SMALLEST_DISP_TYPE (exp->X_add_number);
+ break;
+ case SEG_TEXT: case SEG_DATA: case SEG_BSS:
+ case SEG_UNKNOWN: /* must be 32 bit displacement (i.e. address) */
+ i.types[this_operand] |= Disp32;
+ 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..b9ac3fe
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-i386.h
@@ -0,0 +1,254 @@
+/* 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.1 1993/10/02 20:59:21 pk Exp $
+ */
+
+#ifndef TC_I386
+#define TC_I386 1
+
+#if 0
+#define AOUT_MACHTYPE 100
+#endif
+#define REVERSE_SORT_RELOCS
+
+#define LOCAL_LABELS_FB
+
+#define NO_LISTING
+
+#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..0123138
--- /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..8f9091c
--- /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..caad4d6
--- /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..5f70e42
--- /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..2dac35b
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-m68k.c
@@ -0,0 +1,4076 @@
+/* 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) {
+ case IMMED:
+ tmpreg=0x3c; /* 7.4 */
+ 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;
+
+ /* 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");
+ 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
+
+#ifdef DONTDEF
+/*VARARGS1*/
+panic(format,args)
+char *format;
+{
+ fputs("Internal error:",stderr);
+ _doprnt(format,&args,stderr);
+ (void)putc('\n',stderr);
+ as_where();
+ abort();
+}
+#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..ce69252
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-m68k.h
@@ -0,0 +1,60 @@
+/* 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 TC_M68K 1
+
+#define NO_LISTING
+
+#ifdef OLD_GAS
+#define REVERSE_SORT_RELOCS
+#endif /* OLD_GAS */
+
+#define AOUT_MACHTYPE 0x2
+#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..8d98baf
--- /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..fd7dd86
--- /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..d5960d1
--- /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..02d86c4
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-ns32k.c
@@ -0,0 +1,1923 @@
+/* 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
+
+char comment_chars[] = "#";
+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) },
+ { (8192), (-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 };
+
+
+#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;
+ int j;
+ 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 */
+ 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 */
+ j=(unsigned long)iif.iifP[i].bit_fixP;
+ switch (type) {
+ case 1: /* the object is pure binary */
+ if (j || 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,
+ j,
+ iif.iifP[i].bsr); /* sequent hack */
+ } 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 (j ||
+ 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,
+ j,
+ iif.iifP[i].bsr); /* sequent hack */
+
+ } 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 */
+ 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);
+ 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,
+ (char*)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;
+ 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)
+ 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;
+struct fix *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);
+
+ md_number_to_chars(where,
+ ((long)(r_symbolnum)
+ | (long)(fixP->fx_pcrel << 24)
+ | (long)(nbytes_r_length[fixP->fx_size] << 25)
+ | (long)((!S_IS_DEFINED(fixP->fx_addsy)) << 27)
+ | (long)(fixP->fx_bsr << 28)
+ | (long)(fixP->fx_im_disp << 29)),
+ 4);
+
+ 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 */
+ 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;
+
+ 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)
+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 */
+
+{
+ fixS *fixP = fix_new(frag, where, size, add_symbol, sub_symbol,
+ offset, pcrel, NO_RELOC);
+
+ fixP->fx_pcrel_adjust = pcrel_adjust;
+ fixP->fx_im_disp = im_disp;
+ fixP->fx_bit_fixP = bit_fixP;
+ fixP->fx_bsr = bsr;
+} /* 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..c3c09db
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-ns32k.h
@@ -0,0 +1,60 @@
+/* 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. */
+
+#include "bit_fix.h"
+
+#define NO_LISTING
+
+#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);
+
+#else /* not __STDC__ */
+
+void fix_new_ns32k();
+
+#endif /* not __STDC__ */
+
+
+/* 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..ae50027
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-sparc.c
@@ -0,0 +1,1766 @@
+/* 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.1 1993/11/03 00:54:52 paul 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 *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);
+ /* 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,
+ 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("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 */
+#ifdef PIC
+ the_insn.reloc = flagseen['k']?
+ RELOC_BASE22:
+ RELOC_HI22;
+#else
+ the_insn.reloc = RELOC_HI22;
+#endif
+ 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 */
+#ifdef PIC
+ the_insn.reloc = flagseen['k']?
+ RELOC_JMP_TBL:
+ RELOC_WDISP30;
+#else
+ the_insn.reloc = RELOC_WDISP30;
+#endif
+ 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_BASE13;
+
+ /*FALLTHROUGH */
+
+ immediate:
+ if (*s == ' ')
+ s++;
+ if (*s == '%') {
+ if ((c = s[1]) == 'h' && s[2] == 'i') {
+ 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
+ if (the_insn.exp.X_got_symbol) {
+ switch(the_insn.reloc) {
+ 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;
+ }
+ }
+#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("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:
+ switch (the_insn.reloc) {
+ case RELOC_LO10:
+ the_insn.exp.X_add_number &= ~(~(0) << 10);
+ break;
+ case RELOC_HI22:
+ the_insn.exp.X_add_number &= (~(0) << 10);
+ break;
+ default:
+ break;
+ }
+ break;
+ 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;
+ }
+ switch (the_insn.reloc) {
+ case RELOC_BASE10:
+ case RELOC_BASE13:
+ case RELOC_BASE22:
+ if (the_insn.exp.X_add_symbol)
+ the_insn.exp.X_add_symbol->sy_forceout = 1;
+ break;
+ default:
+ break;
+ }
+ 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("failed sanity check.");
+ }
+ return;
+} /* md_number_to_chars() */
+
+static void reloc_check(val, bits)
+long val;
+int bits;
+{
+ if (((val & (-1 << bits)) != 0)
+ && ((val & (-1 << bits)) != (-1 << (bits - 0)))) {
+ as_warn("Relocation overflow. Value truncated.");
+ } /* on overflow */
+
+ return;
+} /* 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;
+
+#if DEBUG_SPARC
+ 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"
+ };
+ 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:
+ buf[0] = 0; /* val >> 24; */
+ buf[1] = 0; /* val >> 16; */
+ buf[2] = 0; /* val >> 8; */
+ buf[3] = 0; /* val; */
+ 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:
+#endif
+
+ case RELOC_JMP_TBL:
+ case RELOC_WDISP30:
+ val = (val >>= 2) + 1;
+ reloc_check(val, 30);
+
+ buf[0] |= (val >> 24) & 0x3f;
+ buf[1]= (val >> 16);
+ buf[2] = val >> 8;
+ buf[3] = val;
+ break;
+
+
+ case RELOC_HI22:
+ reloc_check(val >> 10, 22);
+
+ if (!fixP->fx_addsy) {
+ buf[1] |= (val >> 26) & 0x3f;
+ buf[2] = val >> 18;
+ buf[3] = val >> 10;
+ } else {
+ buf[2]=0;
+ buf[3]=0;
+ }
+ break;
+
+ case RELOC_PC22:
+ case RELOC_22:
+ reloc_check(val, 22);
+
+ buf[1] |= (val >> 16) & 0x3f;
+ buf[2] = val >> 8;
+ buf[3] = val & 0xff;
+ break;
+
+ case RELOC_13:
+ reloc_check(val, 13);
+
+ buf[2] = (val >> 8) & 0x1f;
+ buf[3] = val & 0xff;
+ break;
+
+
+ case RELOC_PC10:
+ case RELOC_LO10:
+ case RELOC_BASE10:
+ reloc_check(val, 10);
+
+ if (!fixP->fx_addsy) {
+ buf[2] |= (val >> 8) & 0x03;
+ buf[3] = val;
+ } else
+ buf[3]=0;
+ break;
+#if 0
+ case RELOC_SFA_BASE:
+ case RELOC_SFA_OFF13:
+#endif
+ case RELOC_BASE13:
+ reloc_check(val, 13);
+
+ buf[2] |= (val >> 8) & 0x1f;
+ buf[3] = val;
+ break;
+
+ case RELOC_WDISP22:
+ val = (val >>= 2) + 1;
+ /* FALLTHROUGH */
+ case RELOC_BASE22:
+ reloc_check(val, 22);
+
+ 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 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_index = fixP->fx_addsy->sy_number;
+ /*kflag = 1;*/
+ 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;
+{
+ 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"
+ };
+
+ 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..27355a7
--- /dev/null
+++ b/gnu/usr.bin/as/config/tc-sparc.h
@@ -0,0 +1,54 @@
+/* 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.1 1993/10/02 20:59:41 pk Exp $
+ */
+
+#define TC_SPARC 1
+
+#define NO_LISTING
+#define LOCAL_LABELS_FB
+#define WORKING_DOT_WORD
+
+#ifdef OBJ_BOUT
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE ((0x103 << 16) | BMAGIC) /* Magic number for header */
+#else
+#ifdef OBJ_AOUT
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE ((0x103 << 16) | OMAGIC) /* Magic number for header */
+#endif /* OBJ_AOUT */
+#endif /* OBJ_BOUT */
+
+#define AOUT_MACHTYPE 3
+
+#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..68dc5b9
--- /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..e63cb63
--- /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..9133c84
--- /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..4858c7d
--- /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..e559f28
--- /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..1c10191
--- /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..30717ff
--- /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/10/02 20:57:24 pk 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..f2c319f
--- /dev/null
+++ b/gnu/usr.bin/as/doc/Makefile
@@ -0,0 +1,187 @@
+# This file was generated automatically by configure. Do not edit.
+host_alias = i386
+host_cpu = i386
+host_vendor = unknown
+host_os = scosysv322
+target_alias = i386
+target_cpu = i386
+target_vendor = unknown
+target_os = scosysv322
+target_makefile_frag =
+host_makefile_frag =
+site_makefile_frag =
+links =
+VPATH = .
+ALL=all.internal
+# Makefile for GNU Assembler documentation
+# - see pretex.m4 for discussion of preprocessor definitions
+# 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
+
+# What version of the manual you want (see *.m4); "all" includes everything
+CONFIG=all
+
+# Sun/Berkeley m4 doesn't have all the things we need; use GNU or sV
+M4=gm4
+#M4=/usr/5bin/m4
+
+# Directory for gas source
+srcdir = .
+
+# Where to find texinfo.tex to format docn with TeX
+TEXIDIR = $(srcdir)/../texinfo/fsf
+
+#### host, target, and site specific Makefile frags come in here.
+##
+
+all:
+clean:
+install:
+ $(INSTALL_DATA) $(srcdir)/as.1 $(man1dir)/as.1
+
+info: as.info
+
+as.info: as-${CONFIG}.texinfo
+ makeinfo -o as.info as-${CONFIG}.texinfo
+
+install-info: as.info
+ [ -d $(infodir) ] || mkdir $(infodir)
+ for i in as.info* ; do \
+ $(INSTALL_DATA) $$i $(infodir)/$$i ; \
+ done
+
+as.dvi: as-${CONFIG}.texinfo
+ TEXINPUTS=${TEXIDIR}:.:$$TEXINPUTS tex as-${CONFIG}.texinfo
+ texindex as-${CONFIG}.??
+ TEXINPUTS=${TEXIDIR}:.:$$TEXINPUTS tex as-${CONFIG}.texinfo
+ mv as-${CONFIG}.dvi as.dvi
+ rm as-${CONFIG}.?? as-${CONFIG}.???
+
+# ROFF doc targets as.ms, as.mm, as.me
+# (we don't use a variable because we don't trust all makes to handle
+# a var in the target name right).
+# roff output (-ms)
+as.ms: as-${CONFIG}.texinfo
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e 's/{.*,,/{/' \
+ as-${CONFIG}.texinfo | \
+ texi2roff -ms >as.ms
+
+# roff output (-mm)
+as.mm: as-${CONFIG}.texinfo
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e 's/{.*,,/{/' \
+ -e '/@noindent/d' \
+ as-${CONFIG}.texinfo | \
+ texi2roff -mm | \
+ sed -e 's/---/\\(em/g' \
+ >as.mm
+
+# roff output (-me)
+as.me: as-${CONFIG}.texinfo
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e 's/{.*,,/{/' \
+ as-${CONFIG}.texinfo | \
+ texi2roff -me >as.me
+
+
+
+as-all.texinfo: as.texinfo pretex.m4 none.m4 all.m4
+ ${M4} $(srcdir)/pretex.m4 $(srcdir)/none.m4 $(srcdir)/all.m4 $(srcdir)/as.texinfo >as-all.texinfo
+
+as-a29k.texinfo: as.texinfo pretex.m4 none.m4 a29k.m4
+ ${M4} pretex.m4 none.m4 a29k.m4 as.texinfo >as-a29k.texinfo
+
+as-a29k-coff.texinfo: as.texinfo pretex.m4 none.m4 a29k-coff.m4
+ ${M4} pretex.m4 none.m4 a29k-coff.m4 as.texinfo >as-a29k-coff.texinfo
+
+as-gen.texinfo: as.texinfo pretex.m4 none.m4 gen.m4
+ ${M4} pretex.m4 none.m4 gen.m4 as.texinfo >as-gen.texinfo
+
+as-h8.texinfo: as.texinfo pretex.m4 none.m4 h8.m4
+ ${M4} pretex.m4 none.m4 h8.m4 as.texinfo >as-h8.texinfo
+
+as-i80386.texinfo: as.texinfo pretex.m4 none.m4 i80386.m4
+ ${M4} pretex.m4 none.m4 i80386.m4 as.texinfo >as-i80386.texinfo
+
+as-i960.texinfo: as.texinfo pretex.m4 none.m4 i960.m4
+ ${M4} pretex.m4 none.m4 i960.m4 as.texinfo >as-i960.texinfo
+
+as-m680x0.texinfo: as.texinfo pretex.m4 none.m4 m680x0.m4
+ ${M4} pretex.m4 none.m4 m680x0.m4 as.texinfo >as-m680x0.texinfo
+
+as-sparc.texinfo: as.texinfo pretex.m4 none.m4 sparc.m4
+ ${M4} pretex.m4 none.m4 sparc.m4 as.texinfo >as-sparc.texinfo
+
+as-vax.texinfo: as.texinfo pretex.m4 none.m4 vax.m4
+ ${M4} pretex.m4 none.m4 vax.m4 as.texinfo >as-vax.texinfo
+
+as-vintage.texinfo: as.texinfo pretex.m4 none.m4 vintage.m4
+ ${M4} pretex.m4 none.m4 vintage.m4 as.texinfo >as-vintage.texinfo
+
+clean-info:
+ rm -f as-${CONFIG}.* as.dvi as.info*
+
+force:
+
+Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag)
+ $(SHELL) ./config.status
+
diff --git a/gnu/usr.bin/as/doc/Makefile.in b/gnu/usr.bin/as/doc/Makefile.in
new file mode 100644
index 0000000..fdae0b2
--- /dev/null
+++ b/gnu/usr.bin/as/doc/Makefile.in
@@ -0,0 +1,172 @@
+# Makefile for GNU Assembler documentation
+# - see pretex.m4 for discussion of preprocessor definitions
+# 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
+
+# What version of the manual you want (see *.m4); "all" includes everything
+CONFIG=all
+
+# Sun/Berkeley m4 doesn't have all the things we need; use GNU or sV
+M4=gm4
+#M4=/usr/5bin/m4
+
+# Directory for gas source
+srcdir=..
+
+# Where to find texinfo.tex to format docn with TeX
+TEXIDIR = $(srcdir)/../texinfo/fsf
+
+#### host, target, and site specific Makefile frags come in here.
+##
+
+all:
+clean:
+install:
+ $(INSTALL_DATA) $(srcdir)/as.1 $(man1dir)/as.1
+
+info: as.info
+
+as.info: as-${CONFIG}.texinfo
+ makeinfo -o as.info as-${CONFIG}.texinfo
+
+install-info: as.info
+ [ -d $(infodir) ] || mkdir $(infodir)
+ for i in as.info* ; do \
+ $(INSTALL_DATA) $$i $(infodir)/$$i ; \
+ done
+
+as.dvi: as-${CONFIG}.texinfo
+ TEXINPUTS=${TEXIDIR}:.:$$TEXINPUTS tex as-${CONFIG}.texinfo
+ texindex as-${CONFIG}.??
+ TEXINPUTS=${TEXIDIR}:.:$$TEXINPUTS tex as-${CONFIG}.texinfo
+ mv as-${CONFIG}.dvi as.dvi
+ rm as-${CONFIG}.?? as-${CONFIG}.???
+
+# ROFF doc targets as.ms, as.mm, as.me
+# (we don't use a variable because we don't trust all makes to handle
+# a var in the target name right).
+# roff output (-ms)
+as.ms: as-${CONFIG}.texinfo
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e 's/{.*,,/{/' \
+ as-${CONFIG}.texinfo | \
+ texi2roff -ms >as.ms
+
+# roff output (-mm)
+as.mm: as-${CONFIG}.texinfo
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e 's/{.*,,/{/' \
+ -e '/@noindent/d' \
+ as-${CONFIG}.texinfo | \
+ texi2roff -mm | \
+ sed -e 's/---/\\(em/g' \
+ >as.mm
+
+# roff output (-me)
+as.me: as-${CONFIG}.texinfo
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e 's/{.*,,/{/' \
+ as-${CONFIG}.texinfo | \
+ texi2roff -me >as.me
+
+
+
+as-all.texinfo: as.texinfo pretex.m4 none.m4 all.m4
+ ${M4} $(srcdir)/pretex.m4 $(srcdir)/none.m4 $(srcdir)/all.m4 $(srcdir)/as.texinfo >as-all.texinfo
+
+as-a29k.texinfo: as.texinfo pretex.m4 none.m4 a29k.m4
+ ${M4} pretex.m4 none.m4 a29k.m4 as.texinfo >as-a29k.texinfo
+
+as-a29k-coff.texinfo: as.texinfo pretex.m4 none.m4 a29k-coff.m4
+ ${M4} pretex.m4 none.m4 a29k-coff.m4 as.texinfo >as-a29k-coff.texinfo
+
+as-gen.texinfo: as.texinfo pretex.m4 none.m4 gen.m4
+ ${M4} pretex.m4 none.m4 gen.m4 as.texinfo >as-gen.texinfo
+
+as-h8.texinfo: as.texinfo pretex.m4 none.m4 h8.m4
+ ${M4} pretex.m4 none.m4 h8.m4 as.texinfo >as-h8.texinfo
+
+as-i80386.texinfo: as.texinfo pretex.m4 none.m4 i80386.m4
+ ${M4} pretex.m4 none.m4 i80386.m4 as.texinfo >as-i80386.texinfo
+
+as-i960.texinfo: as.texinfo pretex.m4 none.m4 i960.m4
+ ${M4} pretex.m4 none.m4 i960.m4 as.texinfo >as-i960.texinfo
+
+as-m680x0.texinfo: as.texinfo pretex.m4 none.m4 m680x0.m4
+ ${M4} pretex.m4 none.m4 m680x0.m4 as.texinfo >as-m680x0.texinfo
+
+as-sparc.texinfo: as.texinfo pretex.m4 none.m4 sparc.m4
+ ${M4} pretex.m4 none.m4 sparc.m4 as.texinfo >as-sparc.texinfo
+
+as-vax.texinfo: as.texinfo pretex.m4 none.m4 vax.m4
+ ${M4} pretex.m4 none.m4 vax.m4 as.texinfo >as-vax.texinfo
+
+as-vintage.texinfo: as.texinfo pretex.m4 none.m4 vintage.m4
+ ${M4} pretex.m4 none.m4 vintage.m4 as.texinfo >as-vintage.texinfo
+
+clean-info:
+ rm -f as-${CONFIG}.* as.dvi as.info*
+
+force:
+
+Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag)
+ $(SHELL) ./config.status
+
diff --git a/gnu/usr.bin/as/doc/a29k-coff.m4 b/gnu/usr.bin/as/doc/a29k-coff.m4
new file mode 100644
index 0000000..c3b04e1
--- /dev/null
+++ b/gnu/usr.bin/as/doc/a29k-coff.m4
@@ -0,0 +1,14 @@
+_divert__(-1)
+_define__(<_A29K__>,<1>)
+_define__(<_GENERIC__>,<0>)
+_define__(<_HOST__>,<AMD 29K>)
+_define__(<_MACH_DEP__>,<AMD29K-Dependent>)
+_define__(<_AOUT__>,<0>)
+_define__(<_BOUT__>,<0>)
+_define__(<_COFF__>,<1>)
+_define__(<_ELF__>,<0>)
+_define__(<_DIFFTABKLUG__>,0) NO difference-table kluge
+_define__(<_IEEEFLOAT__>,1) IEEE floating point
+_define__(<_W32__>,1) 32-bit words
+_define__(<_W16__>,0)
+_divert__<>
diff --git a/gnu/usr.bin/as/doc/a29k.m4 b/gnu/usr.bin/as/doc/a29k.m4
new file mode 100644
index 0000000..9564387
--- /dev/null
+++ b/gnu/usr.bin/as/doc/a29k.m4
@@ -0,0 +1,9 @@
+_divert__(-1)
+_define__(<_A29K__>,<1>)
+_define__(<_HOST__>,<AMD 29K>)
+_define__(<_MACH_DEP__>,<AMD29K-Dependent>)
+_define__(<_DIFFTABKLUG__>,0) NO difference-table kluge
+_define__(<_IEEEFLOAT__>,1) IEEE floating point
+_define__(<_W32__>,1) 32-bit words
+_define__(<_W16__>,0)
+_divert__<>
diff --git a/gnu/usr.bin/as/doc/all.m4 b/gnu/usr.bin/as/doc/all.m4
new file mode 100644
index 0000000..3d4e7fd
--- /dev/null
+++ b/gnu/usr.bin/as/doc/all.m4
@@ -0,0 +1,20 @@
+_divert__(-1)
+<$Id: all.m4,v 1.1 1993/10/02 21:00:13 pk Exp $>
+_define__(<_ALL_ARCH__>,<1>)
+_define__(<_GENERIC__>,<1>) In case none.m4 changes its mind abt default
+
+_define__(<_AOUT__>,<1>)
+_define__(<_BOUT__>,<1>)
+_define__(<_COFF__>,<1>)
+_define__(<_ELF__>,<1>)
+
+_define__(<_A29K__>,<1>)
+_define__(<_H8__>,<1>)
+_define__(<_I80386__>,<1>)
+_define__(<_I960__>,<1>)
+_define__(<_M680X0__>,<1>)
+_define__(<_SPARC__>,<1>)
+_define__(<_VAX__>,<1>)
+_define__(<_VXWORKS__>,<1>)
+
+_divert__<>
diff --git a/gnu/usr.bin/as/doc/as.texinfo b/gnu/usr.bin/as/doc/as.texinfo
new file mode 100644
index 0000000..c9e0f57
--- /dev/null
+++ b/gnu/usr.bin/as/doc/as.texinfo
@@ -0,0 +1,6730 @@
+_dnl__ -*-Texinfo-*-
+_dnl__ Copyright (c) 1991 1992 Free Software Foundation, Inc.
+_dnl__ $Id: as.texinfo,v 1.1 1993/10/02 21:00:15 pk Exp $
+\input texinfo @c -*-Texinfo-*-
+@c Copyright (c) 1991 1992 Free Software Foundation, Inc.
+@c %**start of header
+@setfilename _AS__.info
+_if__(_GENERIC__)
+@settitle Using _AS__
+_fi__(_GENERIC__)
+_if__(!_GENERIC__)
+@settitle Using _AS__ (_HOST__)
+_fi__(!_GENERIC__)
+@setchapternewpage odd
+@c @smallbook
+@c @cropmarks
+@c %**end of header
+
+@finalout
+@syncodeindex ky cp
+
+_if__(0)
+
+NOTE: this manual is marked up for preprocessing with a collection
+of m4 macros called "pretex.m4".
+
+THIS IS THE FULL SOURCE. The full source needs to be run through m4
+before either tex- or info- formatting: for example,
+ m4 pretex.m4 none.m4 m680x0.m4 as.texinfo >as-680x0.texinfo
+will produce (assuming your path finds either GNU or SysV m4; Berkeley
+won't do) a file, configured for the M680x0 version of GAS, suitable for
+formatting. See the text in "pretex.m4" for a fuller explanation (and
+the macro definitions).
+
+_fi__(0)
+@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
+_if__(!_GENERIC__)
+@subtitle for the _HOST__ family
+_fi__(!_GENERIC__)
+@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__}.
+_if__(!_GENERIC__)
+This version of the file describes @code{_AS__} configured to generate
+code for _HOST__ architectures.
+_fi__(!_GENERIC__)
+@end ifinfo
+@menu
+* Overview:: Overview
+* Invoking:: Command-Line Options
+* Syntax:: Syntax
+* Sections:: Sections and Relocation
+* Symbols:: Symbols
+* Expressions:: Expressions
+* Pseudo Ops:: Assembler Directives
+* _MACH_DEP__:: 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__}.
+_if__(!_GENERIC__)
+This version of the manual describes @code{_AS__} configured to generate
+code for _HOST__ architectures.
+_fi__(!_GENERIC__)
+@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 ]
+_if__(_A29K__)
+@c am29k has no machine-dependent assembler options
+_fi__(_A29K__)
+_if__(_H8__)
+@c h8/300 has no machine-dependent assembler options
+_fi__(_H8__)
+_if__(_I960__)
+@c see md_parse_option in i960.c
+ [ -ACA | -ACA_A | -ACB | -ACC | -AKA | -AKB | -AKC | -AMC ]
+ [ -b ] [ -norelax ]
+_fi__(_I960__)
+_if__(_M680X0__)
+ [ -l ] [ -mc68000 | -mc68010 | -mc68020 ]
+_fi__(_M680X0__)
+ [ -- | @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
+_if__((!_GENERIC__) && !_DIFFTABKLUG__)
+This option is accepted but has no effect on the _HOST__ family.
+_fi__((!_GENERIC__) && !_DIFFTABKLUG__)
+_if__(_GENERIC__ || _DIFFTABKLUG__)
+Issue warnings when difference tables altered for long displacements.
+_fi__(_GENERIC__ || _DIFFTABKLUG__)
+
+@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
+
+_if__(_I960__)
+@item -ACA | -ACA_A | -ACB | -ACC | -AKA | -AKB | -AKC | -AMC
+_if__(_GENERIC__)
+(When configured for Intel 960).
+_fi__(_GENERIC__)
+Specify which variant of the 960 architecture is the target.
+
+@item -b
+_if__(_GENERIC__)
+(When configured for Intel 960).
+_fi__(_GENERIC__)
+Add code to collect statistics about branches taken.
+
+@item -norelax
+_if__(_GENERIC__)
+(When configured for Intel 960).
+_fi__(_GENERIC__)
+Do not alter compare-and-branch instructions for long displacements;
+error if necessary.
+_fi__(_I960__)
+
+_if__(_M680X0__)
+@item -l
+_if__(_GENERIC__)
+(When configured for Motorola 68000).
+_fi__(_GENERIC__)
+Shorten references to undefined symbols, to one word instead of two
+
+@item -mc68000 | -mc68010 | -mc68020
+_if__(_GENERIC__)
+(When configured for Motorola 68000).
+_fi__(_GENERIC__)
+Specify what processor in the 68000 family is the target (default 68020)
+_fi__(_M680X0__)
+
+@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__}.
+
+_if__(!_GENERIC__)
+We also cover special features in the _HOST__
+configuration of @code{_AS__}, including assembler directives.
+_fi__(!_GENERIC__)
+_if__(_GENERIC__)
+This manual also describes some of the machine-dependent features of
+various flavors of the assembler.
+_fi__(_GENERIC__)
+_if__(_INTERNALS__)
+This manual also describes how the assembler works internally, and
+provides some information that may be useful to people attempting to
+port the assembler to another machine.
+_fi__(_INTERNALS__)
+@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.
+_if__(_GENERIC__)
+You may want to consult the manufacturer's
+machine architecture manual for this information.
+_fi__(_GENERIC__)
+_if__(_H8__&&!_GENERIC__)
+For information on the H8/300 machine instruction set, see @cite{H8/300
+Series Programming Manual} (Hitachi ADE--602--025).
+_fi__(_H8__&&!_GENERIC__)
+
+
+@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__(!_GENERIC__)
+This manual describes @code{_AS__}, a member of that family which is
+configured for the _HOST__ architectures.
+_fi__(!_GENERIC__)
+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
+
+_if__(_GENERIC__||!_H8__)
+@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.
+_fi__(_GENERIC__||!_H8__)
+_if__(_VAX__)
+Any exceptions are documented explicitly (@pxref{_MACH_DEP__}).
+_fi__(_VAX__)
+_if__(_GENERIC__||_M680X0__)
+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.
+_fi__(_GENERIC__||_M680X0__)
+
+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}.
+_if__(!_GENERIC__)
+_if__(!(_I960__||_A29K__))
+_if__(_AOUT__ && (!_COFF__) && (!_ELF__))
+On the _HOST__, @code{_AS__} is configured to produce @code{a.out} format object
+files.@refill
+_fi__(_AOUT__ && (!_COFF__) && (!_ELF__))
+_if__((!_AOUT__) && _COFF__ && (!_ELF__))
+On the _HOST__, @code{_AS__} is configured to produce COFF format object
+files.@refill
+_fi__((!_AOUT__) && _COFF__ && (!_ELF__))
+_fi__(!(_I960__||_A29K__))
+_if__(_A29K__)
+On the _HOST__, @code{_AS__} can be configured to produce either
+@code{a.out} or COFF format object files.
+_fi__(_A29K__)
+_if__(_I960__)
+On the _HOST__, @code{_AS__} can be configured to produce either @code{b.out} or COFF
+format object files.
+_fi__(_I960__)
+_fi__(!_GENERIC__)
+
+@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
+_if__(!_A29K__)
+(@pxref{Line,,@code{.line}})
+_fi__(!_A29K__)
+_if__(_A29K__)
+(@pxref{Ln,,@code{.ln}})
+_fi__(_A29K__)
+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{_MACH_DEP__}, for options specific
+_if__(!_GENERIC__)
+to the _HOST__.
+_fi__(!_GENERIC__)
+_if__(_GENERIC__)
+to particular machine architectures.
+_fi__(_GENERIC__)
+
+@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
+_if__((!_GENERIC__) && (!_DIFFTABKLUG__))
+On the _HOST__ family, this option is allowed, but has no effect. It is
+permitted for compatibility with the GNU assembler on other platforms,
+where it can be used to warn when the assembler alters the machine code
+generated for @samp{.word} directives in difference tables. The _HOST__
+family does not have the addressing limitations that sometimes lead to this
+alteration on other platforms.
+_fi__((!_GENERIC__) && (!_DIFFTABKLUG__))
+
+_if__(_GENERIC__ || _DIFFTABKLUG__ )
+@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.
+_fi__(_GENERIC__ || _DIFFTABKLUG__ )
+
+@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.
+
+_if__(_COFF__)
+When @code{_AS__} is configured for COFF output,
+this option is only useful if you use sections named @samp{.text} and
+@samp{.data}.
+_fi__(_COFF__)
+
+@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
+_if__(!_VAX__)
+assembler. @refill
+_fi__(!_VAX__)
+_if__(_VAX__)
+assembler, except that @code{_AS__} does not assemble Vax bit-fields.
+_fi__(_VAX__)
+
+@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
+_if__(_VAX__)
+@samp{#} on the Vax;
+_fi__(_VAX__)
+_if__(_I960__)
+@samp{#} on the i960;
+_fi__(_I960__)
+_if__(_M680X0__)
+@samp{|} on the 680x0;
+_fi__(_M680X0__)
+_if__(_A29K__)
+@samp{;} for the AMD 29K family;
+_fi__(_A29K__)
+_if__(_H8__)
+@samp{;} for the _HOST__ family;
+_fi__(_H8__)
+@pxref{_MACH_DEP__}. @refill
+@c FIXME: fill in SPARC line comment char
+
+_if__(_GENERIC__)
+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.
+_fi__(_GENERIC__)
+
+@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
+_if__(!_H8__)
+the three characters @samp{_.$}
+_fi__(!_H8__)
+_if__(_H8__)
+the two characters @samp{_.}
+_if__(_GENERIC__)
+On most machines, you can also use @code{$} in symbol names; exceptions
+are noted in @ref{_MACH_DEP__}.
+_fi__(_GENERIC__)
+_fi__(_H8__)
+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
+_if__(!_GENERIC__)
+_if__(!(_A29K__||_H8__))
+A @dfn{statement} ends at a newline character (@samp{\n}) or at a
+semicolon (@samp{;}). The newline or semicolon is considered part of
+the preceding statement. Newlines and semicolons within character
+constants are an exception: they don't end statements.
+_fi__(!(_A29K__||_H8__))
+_if__(_A29K__)
+A @dfn{statement} ends at a newline character (@samp{\n}) or an ``at''
+sign (@samp{@@}). The newline or at sign is considered part of the
+preceding statement. Newlines and at signs within character constants
+are an exception: they don't end statements.
+_fi__(_A29K__)
+_if__(_H8__)
+A @dfn{statement} ends at a newline character (@samp{\n}) or a dollar
+sign (@samp{$}). The newline or dollar sign is considered part of the
+preceding statement. Newlines and dollar signs within character constants
+are an exception: they don't end statements.
+_fi__(_H8__)
+_fi__(!_GENERIC__)
+_if__(_GENERIC__)
+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{_MACH_DEP__}.) 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.
+_fi__(_GENERIC__)
+
+@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.
+_if__(_GENERIC__)
+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
+_fi__(_GENERIC__)
+
+@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
+_if__(!_GENERIC__)
+_if__(!(_A29K__||_H8__))
+(or semicolon @samp{;})
+_fi__(!(_A29K__||_H8__))
+_if__(_A29K__)
+(or at sign @samp{@@})
+_fi__(_A29K__)
+_if__(_H8__)
+(or dollar sign @samp{$})
+_fi__(_H8__)
+_fi__(!_GENERIC__)
+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
+_if__(_I960__&&!_GENERIC__)
+* Bit Fields:: Bit Fields
+_fi__(_I960__&&!_GENERIC__)
+@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.
+
+_if__(_I960__&&!_GENERIC__)
+@node Flonums, Bit Fields, Bignums, Numbers
+_fi__(_I960__&&!_GENERIC__)
+_if__(_GENERIC__||!_I960__)
+@node Flonums, , Bignums, Numbers
+_fi__(_GENERIC__||!_I960__)
+@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.
+_if__(_GENERIC__)
+@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
+_fi__(_GENERIC__)
+_if__(_A29K__||_H8__)
+_if__(_GENERIC__)
+On the AMD 29K and H8/300 architectures, the letter must be:
+_fi__(_GENERIC__)
+One of the letters @samp{DFPRSX} (in upper or lower case).
+_fi__(_A29K__||_H8__)
+_if__(_I960__)
+_if__(_GENERIC__)
+On the Intel 960 architecture, the letter must be:
+_fi__(_GENERIC__)
+One of the letters @samp{DFT} (in upper or lower case).
+_fi__(_I960__)
+@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__}.
+
+_if__(_I960__&&!_GENERIC__)
+@c Bit fields are written as a general facility but are also controlled
+@c by a conditional-compilation flag---which is as of now (21mar91)
+@c turned on only by the i960 config of GAS.
+@node Bit Fields, , Flonums, Numbers
+@subsubsection Bit Fields
+
+@cindex bit fields
+@cindex constants, bit field
+You can also define numeric constants as @dfn{bit fields}.
+specify two numbers separated by a colon---
+@example
+@var{mask}:@var{value}
+@end example
+@noindent
+the first will act as a mask; @code{_AS__} will bitwise-and it with the
+second value.
+
+The resulting number is then packed
+_if__(_GENERIC__)
+@c this conditional paren in case bit fields turned on elsewhere than 960
+(in host-dependent byte order)
+_fi__(_GENERIC__)
+into a field whose width depends on which assembler directive has the
+bit-field as its argument. Overflow (a result from the bitwise and
+requiring more binary digits to represent) is not an error; instead,
+more constants are generated, of the specified width, beginning with the
+least significant digits.@refill
+
+The directives @code{.byte}, @code{.hword}, @code{.int}, @code{.long},
+@code{.short}, and @code{.word} accept bit-field arguments.
+_fi__(_I960__&&!_GENERIC__)
+
+@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.
+_if__(_H8__)
+For the H8/300, @code{_AS__} pads sections if needed to ensure they end
+on a word (sixteen bit) boundary.
+_fi__(_H8__)
+
+@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.
+
+_if__(_COFF__)
+_if__(_GENERIC__)
+When it generates COFF output,
+_fi__(_GENERIC__)
+@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.
+_fi__(_COFF__)
+
+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
+
+_if__(_GENERIC__||_COFF__)
+@cindex named sections
+@cindex sections, named
+@item named sections
+_fi__(_GENERIC__||_COFF__)
+_if__(_AOUT__||_BOUT__)
+@cindex text section
+@cindex data section
+@item text section
+@itemx data section
+_fi__(_AOUT__||_BOUT__)
+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.
+_if__(_AOUT__||_BOUT__)
+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.
+_fi__(_AOUT__||_BOUT__)
+
+@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.
+_if__(_COFF__)
+The example uses the traditional section names @samp{.text} and @samp{.data}.
+_fi__(_COFF__)
+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
+_if__(_AOUT__||_BOUT__)
+Assembled bytes
+_if__(_COFF__)
+conventionally
+_fi__(_COFF__)
+fall into two sections: text and data.
+_fi__(_AOUT__||_BOUT__)
+You may have separate groups of
+_if__(_COFF__||_GENERIC__)
+data in named sections
+_fi__(_COFF__||_GENERIC__)
+_if__((_AOUT__||_BOUT__)&&!_GENERIC__)
+text or data
+_fi__((_AOUT__||_BOUT__)&&!_GENERIC__)
+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.
+
+_if__(_GENERIC__)
+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__}.)
+_fi__(_GENERIC__)
+_if__(!_GENERIC__)
+_if__(_H8__)
+On the H8/300 platform, each subsection is zero-padded to a word
+boundary (two bytes).
+_fi__(_H8__)
+_if__(_I960__)
+@c FIXME section padding (alignment)?
+@c Rich Pixley says padding here depends on target obj code format; that
+@c doesn't seem particularly useful to say without further elaboration,
+@c so for now I say nothing about it. If this is a generic BFD issue,
+@c these paragraphs might need to vanish from this manual, and be
+@c discussed in BFD chapter of binutils (or some such).
+_fi__(_I960__)
+_if__(_A29K__)
+On the AMD 29K family, no particular padding is added to section or
+subsection sizes; _AS__ forces no alignment on this platform.
+_fi__(_A29K__)
+_fi__(!_GENERIC__)
+
+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.
+_if__(_COFF__)
+_if__(_GENERIC__)
+When generating COFF output, you
+_fi__(_GENERIC__)
+_if__(!_GENERIC__)
+You
+_fi__(!_GENERIC__)
+can also use an extra subsection
+argument with arbitrary named sections: @samp{.section @var{name},
+@var{expression}}.
+_fi__(_COFF__)
+@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
+_if__(!_H8__)
+@samp{_.$}
+_fi__(!_H8__)
+_if__(_H8__)
+@samp{_.}
+_if__(_GENERIC__)
+(On most machines, you can also use @code{$} in symbol names; exceptions
+are noted in @ref{_MACH_DEP__}.)
+_fi__(_GENERIC__)
+_fi__(_H8__)
+That character may be followed by any string of digits, letters,
+_if__(!_H8__)
+underscores and dollar signs.
+_fi__(!_H8__)
+_if__(_H8__)
+_if__(_GENERIC__)
+dollar signs (unless otherwise noted in @ref{_MACH_DEP__}),
+_fi__(_GENERIC__)
+and underscores.
+_fi__(_H8__)
+Case of letters is significant:
+@code{foo} is a different symbol name than @code{Foo}.
+
+_if__(_A29K__)
+For the AMD 29K family, @samp{?} is also allowed in the
+body of a symbol name, though not at its beginning.
+_fi__(_A29K__)
+
+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
+_if__(!_A29K__)
+@samp{.space 4}.
+_fi__(!_A29K__)
+_if__(_A29K__)
+@samp{.block 4}.
+_fi__(_A29K__)
+
+@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__(_INTERNALS__)
+The detailed definitions are in _0__<a.out.h>_1__.
+_fi__(_INTERNALS__)
+
+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
+_if__(_AOUT__||_BOUT__)
+_if__(_GENERIC__||!_BOUT__)
+* a.out Symbols:: Symbol Attributes: @code{a.out}
+_fi__(_GENERIC__||!_BOUT__)
+_if__(_BOUT__&&!_GENERIC__)
+* a.out Symbols:: Symbol Attributes: @code{a.out}, @code{b.out}
+_fi__(_BOUT__&&!_GENERIC__)
+_fi__(_AOUT__||_BOUT__)
+_if__(_COFF__)
+* COFF Symbols:: Symbol Attributes for COFF
+_fi__(_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.
+
+_if__(!(_AOUT__||_BOUT__))
+@node Symbol Type, COFF Symbols, Symbol Value, Symbol Attributes
+_fi__(!(_AOUT__||_BOUT__))
+_if__((_AOUT__||_BOUT__))
+@node Symbol Type, a.out Symbols, Symbol Value, Symbol Attributes
+_fi__((_AOUT__||_BOUT__))
+@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.
+
+_if__(_AOUT__||_BOUT__)
+_if__(_COFF__)
+@node a.out Symbols, COFF Symbols, Symbol Type, Symbol Attributes
+_fi__(_COFF__)
+_if__(!_COFF__)
+@node a.out Symbols, , Symbol Type, Symbol Attributes
+_fi__(!_COFF__)
+_if__(_BOUT__&&!_GENERIC__)
+@subsection Symbol Attributes: @code{a.out}, @code{b.out}
+
+@cindex @code{b.out} symbol attributes
+@cindex symbol attributes, @code{b.out}
+These symbol attributes appear only when @code{_AS__} is configured for
+one of the Berkeley-descended object output formats.
+_fi__(_BOUT__&&!_GENERIC__)
+_if__(_GENERIC__||!_BOUT__)
+@subsection Symbol Attributes: @code{a.out}
+_fi__(_GENERIC__||!_BOUT__)
+
+@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__}.
+_fi__(_AOUT__||_BOUT__)
+
+_if__(_COFF__)
+_if__(!(_AOUT__||_BOUT__))
+@node COFF Symbols, , Symbol Type, Symbol Attributes
+_fi__(!(_AOUT__||_BOUT__))
+_if__(_AOUT__||_BOUT__)
+@node COFF Symbols, , a.out Symbols, Symbol Attributes
+_fi__(_AOUT__||_BOUT__)
+@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.
+_fi__(_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 _0__<_1__
+@itemx _0__<<_1__
+@dfn{Shift Left}. Same as the C operator @samp{_0__<<_1__}
+
+@item _0__>_1__
+@itemx _0__>>_1__
+@dfn{Shift Right}. Same as the C operator @samp{_0__>>_1__}
+@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, _MACH_DEP__, 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.
+_if__(!_H8__)
+@xref{_MACH_DEP__} for additional directives.
+_fi__(!_H8__)
+
+@menu
+* Abort:: @code{.abort}
+_if__(_COFF__)
+* coff-ABORT:: @code{.ABORT}
+_fi__(_COFF__)
+_if__(_BOUT__&&!_COFF__)
+* bout-ABORT:: @code{.ABORT}
+_fi__(_BOUT__&&!_COFF__)
+* 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}}
+_if__(_COFF__||_BOUT__)
+* Def:: @code{.def @var{name}}
+_fi__(_COFF__||_BOUT__)
+_if__(_AOUT__||_BOUT__)
+* Desc:: @code{.desc @var{symbol}, @var{abs-expression}}
+_fi__(_AOUT__||_BOUT__)
+_if__(_COFF__||_BOUT__)
+* Dim:: @code{.dim}
+_fi__(_COFF__||_BOUT__)
+* Double:: @code{.double @var{flonums}}
+* Eject:: @code{.eject}
+* Else:: @code{.else}
+_if__(_COFF__||_BOUT__)
+* Endef:: @code{.endef}
+_fi__(_COFF__||_BOUT__)
+* Endif:: @code{.endif}
+* Equ:: @code{.equ @var{symbol}, @var{expression}}
+* Extern:: @code{.extern}
+_if__(_GENERIC__||!_A29K__)
+* File:: @code{.file @var{string}}
+_fi__(_GENERIC__||!_A29K__)
+* 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}
+_if__(_GENERIC__||!_A29K__)
+* Line:: @code{.line @var{line-number}}
+_fi__(_GENERIC__||!_A29K__)
+* 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}"}
+_if__(_COFF__||_BOUT__)
+* Scl:: @code{.scl @var{class}}
+_fi__(_COFF__||_BOUT__)
+_if__(_COFF__)
+* Section:: @code{.section @var{name}, @var{subsection}}
+_fi__(_COFF__)
+* Set:: @code{.set @var{symbol}, @var{expression}}
+* Short:: @code{.short @var{expressions}}
+* Single:: @code{.single @var{flonums}}
+_if__(_COFF__||_BOUT__)
+* Size:: @code{.size}
+_fi__(_COFF__||_BOUT__)
+* Space:: @code{.space @var{size} , @var{fill}}
+_if__(_GENERIC__||!_H8__)
+* Stab:: @code{.stabd, .stabn, .stabs}
+_fi__(_GENERIC__||!_H8__)
+_if__(_COFF__||_BOUT__)
+* Tag:: @code{.tag @var{structname}}
+_fi__(_COFF__||_BOUT__)
+* Text:: @code{.text @var{subsection}}
+* Title:: @code{.title "@var{heading}"}
+_if__(_COFF__||_BOUT__)
+* Type:: @code{.type @var{int}}
+* Val:: @code{.val @var{addr}}
+_fi__(_COFF__||_BOUT__)
+* Word:: @code{.word @var{expressions}}
+* Deprecated:: Deprecated Directives
+@end menu
+
+_if__(_COFF__)
+@node Abort, coff-ABORT, Pseudo Ops, Pseudo Ops
+_fi__(_COFF__)
+_if__((!_COFF__) && _BOUT__)
+@node Abort, bout-ABORT, Pseudo Ops, Pseudo Ops
+_fi__((!_COFF__) && _BOUT__)
+_if__(! (_BOUT__ || _COFF__) )
+@node Abort, Align, Pseudo Ops, Pseudo Ops
+_fi__(! (_BOUT__ || _COFF__) )
+@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.
+
+_if__(_COFF__)
+@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}.
+_fi__(_COFF__)
+
+_if__(_BOUT__)
+_if__(!_COFF__)
+@node bout-ABORT, Align, Abort, Pseudo Ops
+@section @code{.ABORT}
+
+@cindex @code{ABORT} directive
+_fi__(!_COFF__)
+
+When producing @code{b.out} output, @code{_AS__} accepts this directive,
+but ignores it.
+_fi__(_BOUT__)
+
+_if__( ! (_COFF__ || _BOUT__) )
+@node Align, App-File, Abort, Pseudo Ops
+_fi__( ! (_COFF__ || _BOUT__) )
+_if__( _COFF__)
+@node Align, App-File, coff-ABORT, Pseudo Ops
+_fi__( _COFF__)
+_if__( _BOUT__ && (! _COFF__))
+@node Align, App-File, bout-ABORT, Pseudo Ops
+_fi__( _BOUT__ && (! _COFF__))
+@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}
+_if__(!_A29K__)
+(which may also be spelled @samp{.file})
+_fi__(!_A29K__)
+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.
+
+_if__(_COFF__ || _BOUT__)
+@node Data, Def, Comm, Pseudo Ops
+_fi__(_COFF__ || _BOUT__)
+_if__(!(_COFF__ || _BOUT__) && _AOUT__)
+@node Data, Desc, Comm, Pseudo Ops
+_fi__(!(_COFF__ || _BOUT__) && _AOUT__)
+_if__(! (_COFF__ || _BOUT__ || _AOUT__) )
+@c Well, this *might* happen...
+@node Data, Double, Comm, Pseudo Ops
+_fi__(! (_COFF__ || _BOUT__ || _AOUT__) )
+@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.
+
+_if__(_COFF__ || _BOUT__)
+_if__(_AOUT__ || _BOUT__)
+@node Def, Desc, Data, Pseudo Ops
+_fi__(_AOUT__ || _BOUT__)
+_if__(!(_AOUT__ || _BOUT__))
+@node Def, Dim, Data, Pseudo Ops
+_fi__(!(_AOUT__ || _BOUT__))
+@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.
+_if__(_BOUT__)
+
+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.
+_fi__(_BOUT__)
+_fi__(_COFF__ || _BOUT__)
+
+_if__(_AOUT__||_BOUT__)
+_if__(_COFF__||_BOUT__)
+@node Desc, Dim, Def, Pseudo Ops
+_fi__(_COFF__||_BOUT__)
+_if__(!(_COFF__||_BOUT__))
+@node Desc, Double, Data, Pseudo Ops
+_fi__(!(_COFF__||_BOUT__))
+@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.
+
+_if__(_COFF__)
+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.
+_fi__(_COFF__)
+_fi__(_AOUT__||_BOUT__)
+
+_if__(_COFF__ || _BOUT__)
+_if__(_AOUT__ || _BOUT__)
+@node Dim, Double, Desc, Pseudo Ops
+_fi__(_AOUT__ || _BOUT__)
+_if__(!(_AOUT__ || _BOUT__))
+@node Dim, Double, Def, Pseudo Ops
+_fi__(!(_AOUT__ || _BOUT__))
+@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.
+_if__(_BOUT__)
+
+@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.
+_fi__(_BOUT__)
+_fi__(_COFF__ || _BOUT__)
+
+_if__(_COFF__||_BOUT__)
+@node Double, Eject, Dim, Pseudo Ops
+_fi__(_COFF__||_BOUT__)
+_if__(!(_COFF__||_BOUT__))
+@node Double, Eject, Desc, Pseudo Ops
+_fi__(!(_COFF__||_BOUT__))
+@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.
+_if__(_GENERIC__)
+The exact kind of floating point numbers emitted depends on how
+@code{_AS__} is configured. @xref{_MACH_DEP__}.
+_fi__(_GENERIC__)
+_if__((!_GENERIC__) && _IEEEFLOAT__)
+On the _HOST__ family @samp{.double} emits 64-bit floating-point numbers
+in @sc{ieee} format.
+_fi__((!_GENERIC__) && _IEEEFLOAT__)
+
+@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.
+
+_if__(_COFF__||_BOUT__)
+@node Else, Endef, Eject, Pseudo Ops
+_fi__(_COFF__||_BOUT__)
+_if__(!(_COFF__||_BOUT__))
+@node Else, Endif, Eject, Pseudo Ops
+_fi__(!(_COFF__||_BOUT__))
+@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.
+
+_if__(0)
+@node End, Endef, Else, Pseudo Ops
+@section @code{.end}
+
+@cindex @code{end} directive
+This doesn't do anything---but isn't an s_ignore, so I suspect it's
+meant to do something eventually (which is why it isn't documented here
+as "for compatibility with blah").
+_fi__(0)
+
+_if__(_COFF__||_BOUT__)
+@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}.
+_if__(_BOUT__)
+
+@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.
+_fi__(_BOUT__)
+_fi__(_COFF__||_BOUT__)
+
+_if__(_COFF__||_BOUT__)
+@node Endif, Equ, Endef, Pseudo Ops
+_fi__(_COFF__||_BOUT__)
+_if__(!(_COFF__||_BOUT__))
+@node Endif, Equ, Else, Pseudo Ops
+_fi__(!(_COFF__||_BOUT__))
+@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}}.
+
+_if__(_GENERIC__||!_A29K__)
+@node Extern, File, Equ, Pseudo Ops
+_fi__(_GENERIC__||!_A29K__)
+_if__(_A29K__&&!_GENERIC__)
+@node Extern, Fill, Equ, Pseudo Ops
+_fi__(_A29K__&&!_GENERIC__)
+@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.
+
+_if__(_GENERIC__||!_A29K__)
+@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.
+_if__(_A29K__)
+In some configurations of @code{_AS__}, @code{.file} has already been
+removed to avoid conflicts with other assemblers. @xref{_MACH_DEP__}.
+_fi__(_A29K__)
+_fi__(_GENERIC__||!_A29K__)
+
+_if__(_GENERIC__||!_A29K__)
+@node Fill, Float, File, Pseudo Ops
+_fi__(_GENERIC__||!_A29K__)
+_if__(_A29K__&&!_GENERIC__)
+@node Fill, Float, Extern, Pseudo Ops
+_fi__(_A29K__&&!_GENERIC__)
+@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}.
+_if__(_GENERIC__)
+The exact kind of floating point numbers emitted depends on how
+@code{_AS__} is configured.
+@xref{_MACH_DEP__}.
+_fi__(_GENERIC__)
+_if__((!_GENERIC__) && _IEEEFLOAT__)
+On the _HOST__ family, @code{.float} emits 32-bit floating point numbers
+in @sc{ieee} format.
+_fi__((!_GENERIC__) && _IEEEFLOAT__)
+
+@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.
+
+_if__(_AOUT__||_BOUT__||_COFF__)
+@node hword, Ident, Global, Pseudo Ops
+_fi__(_AOUT__||_BOUT__||_COFF__)
+_if__(!(_AOUT__||_BOUT__||_COFF__))
+@node hword, If, Global, Pseudo Ops
+_fi__(!(_AOUT__||_BOUT__||_COFF__))
+@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.
+
+_if__(_GENERIC__)
+This directive is a synonym for @samp{.short}; depending on the target
+architecture, it may also be a synonym for @samp{.word}.
+_fi__(_GENERIC__)
+_if__( _W32__ && !_GENERIC__ )
+This directive is a synonym for @samp{.short}.
+_fi__( _W32__ && !_GENERIC__ )
+_if__(_W16__ && !_GENERIC__ )
+This directive is a synonym for both @samp{.short} and @samp{.word}.
+_fi__(_W16__ && !_GENERIC__ )
+
+_if__(_AOUT__||_BOUT__||_COFF__)
+@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.
+_fi__(_AOUT__||_BOUT__||_COFF__)
+
+_if__(_AOUT__||_BOUT__||_COFF__)
+@node If, Include, Ident, Pseudo Ops
+_fi__(_AOUT__||_BOUT__||_COFF__)
+_if__(!(_AOUT__||_BOUT__||_COFF__))
+@node If, Include, hword, Pseudo Ops
+_fi__(!(_AOUT__||_BOUT__||_COFF__))
+@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.
+
+_if__(0)
+@item .ifeqs
+@cindex @code{ifeqs} directive
+Not yet implemented.
+_fi__(0)
+
+@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.
+
+_if__(0)
+@item ifnes
+Not yet implemented.
+_fi__(0)
+@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
+_if__(_GENERIC__||!_H8__)
+@cindex integers, 32-bit
+_fi__(_GENERIC__||!_H8__)
+Expect zero or more @var{expressions}, of any section, separated by
+commas. For each expression, emit a
+_if__(_GENERIC__||!_H8__)
+32-bit
+_fi__(_GENERIC__||!_H8__)
+_if__(_H8__&&!_GENERIC__)
+16-bit
+_fi__(_H8__&&!_GENERIC__)
+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__}.
+
+_if__(_GENERIC__||(!_A29K__))
+@node Lflags, Line, Lcomm, Pseudo Ops
+_fi__(_GENERIC__||(!_A29K__))
+_if__((!_GENERIC__)&& _A29K__)
+@node Lflags, Ln, Lcomm, Pseudo Ops
+_fi__((!_GENERIC__)&& _A29K__)
+@section @code{.lflags}
+
+@cindex @code{lflags} directive (ignored)
+@code{_AS__} accepts this directive, for compatibility with other
+assemblers, but ignores it.
+
+_if__(_GENERIC__ || !_A29K__)
+@node Line, Ln, Lflags, Pseudo Ops
+@section @code{.line @var{line-number}}
+
+@cindex @code{line} directive
+_fi__(_GENERIC__ || (!_A29K__))
+_if__(_A29K__ && (!_GENERIC__))
+@node Ln, List, Lflags, Pseudo Ops
+@section @code{.ln @var{line-number}}
+
+@cindex @code{ln} directive
+_fi__(_A29K__ && (!_GENERIC__))
+@cindex logical line number
+_if__(_AOUT__||_BOUT__)
+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
+_if__(_GENERIC__)
+character)
+_fi__(_GENERIC__)
+_if__(!_GENERIC__)
+_if__(! (_A29K__||_H8__) )
+character @code{;})
+_fi__(! (_A29K__||_H8__) )
+_if__(_A29K__)
+character @samp{@@})
+_fi__(_A29K__)
+_if__(_H8__)
+character @samp{$})
+_fi__(_H8__)
+_fi__(!_GENERIC__)
+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
+
+_if__(_GENERIC__ && _A29K__)
+@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}.
+_fi__(_GENERIC__ && _A29K__)
+_fi__(_AOUT__||_BOUT__)
+_if__(_COFF__)
+
+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.
+_fi__(_COFF__)
+
+_if__(_AOUT__&&(_GENERIC__||!_A29K__))
+@node Ln, List, Line, Pseudo Ops
+@section @code{.ln @var{line-number}}
+
+@cindex @code{ln} directive
+@samp{.ln} is a synonym for @samp{.line}.
+_fi__(_AOUT__&&(_GENERIC__||!_A29K__))
+_if__(_COFF__&&!_AOUT__)
+@node Ln, List, Line, Pseudo Ops
+@section @code{.ln @var{line-number}}
+
+@cindex @code{ln} directive
+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 @code{;}) will be reported as on logical
+line number @var{line-number} @minus{} 1.
+_if__(_BOUT__)
+
+This directive is accepted, but ignored, when @code{_AS__} is configured for
+@code{b.out}; its effect is only associated with COFF output format.
+_fi__(_BOUT__)
+_fi__(_COFF__&&!_AOUT__)
+
+@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
+_if__(_GENERIC__||(!_I960__))
+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.
+_fi__(_GENERIC__||(!_I960__))
+_if__(_I960__&&(!_GENERIC__))
+a 16-byte integer. If the bignum won't fit in 16 bytes, it prints a
+warning message; and just takes the lowest order 16 bytes of the
+bignum.@refill
+@cindex sixteen-byte integer
+@cindex integer, 16-byte
+_fi__(_I960__&&(!_GENERIC__))
+
+_if__(_COFF__||_BOUT__)
+@node Sbttl, Scl, Quad, Pseudo Ops
+_fi__(_COFF__||_BOUT__)
+_if__(!(_COFF__||_BOUT__))
+@node Sbttl, Set, Quad, Pseudo Ops
+_fi__(!(_COFF__||_BOUT__))
+@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.
+
+_if__(_COFF__||_BOUT__)
+_if__(!_COFF__)
+@node Scl, Set, Sbttl, Pseudo Ops
+_fi__(!_COFF__)
+_if__(_COFF__)
+@node Scl, Section, Sbttl, Pseudo Ops
+_fi__(_COFF__)
+@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.
+_if__(_BOUT__)
+
+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.
+_fi__(_BOUT__)
+_fi__(_COFF__||_BOUT__)
+
+_if__(_COFF__)
+@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
+_fi__(_COFF__)
+_if__(_BOUT__&&!_COFF__)
+@node Set, Short, Scl, Pseudo Ops
+_fi__(_BOUT__&&!_COFF__)
+_if__(!(_COFF__||_BOUT__))
+@node Set, Short, Quad, Pseudo Ops
+_fi__(!(_COFF__||_BOUT__))
+@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
+_if__(_GENERIC__ || _W16__)
+@code{.short} is the same as @samp{.word}. @xref{Word,,@code{.word}}.
+_if__(_W32__)
+In some configurations, however, @code{.short} and @code{.word} generate
+numbers of different lengths; @pxref{_MACH_DEP__}.
+_fi__(_W32__)
+_fi__(_GENERIC__|| _W16__)
+_if__((!_GENERIC__) && _W32__)
+This expects zero or more @var{expressions}, and emits
+a 16 bit number for each.
+_fi__((!_GENERIC__) && _W32__)
+_if__(_COFF__||_BOUT__)
+@node Single, Size, Short, Pseudo Ops
+_fi__(_COFF__||_BOUT__)
+_if__(!(_COFF__||_BOUT__))
+@node Single, Space, Short, Pseudo Ops
+_fi__(!(_COFF__||_BOUT__))
+@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}.
+_if__(_GENERIC__)
+The exact kind of floating point numbers emitted depends on how
+@code{_AS__} is configured. @xref{_MACH_DEP__}.
+_fi__(_GENERIC__)
+_if__((!_GENERIC__) && _IEEEFLOAT__)
+On the _HOST__ family, @code{.single} emits 32-bit floating point
+numbers in @sc{ieee} format.
+_fi__((!_GENERIC__) && _IEEEFLOAT__)
+
+_if__(_COFF__||_BOUT__)
+@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.
+_if__(_BOUT__)
+
+@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.
+_fi__(_BOUT__)
+_fi__(_COFF__||_BOUT__)
+
+_if__(_H8__&&!_GENERIC__)
+@node Space, Tag, Size, Pseudo Ops
+_fi__(_H8__&&!_GENERIC__)
+_if__(_GENERIC__||!_H8__)
+_if__(_COFF__||_BOUT__)
+@node Space, Stab, Size, Pseudo Ops
+_fi__(_COFF__||_BOUT__)
+_if__(!(_COFF__||_BOUT__))
+@node Space, Stab, Single, Pseudo Ops
+_fi__(!(_COFF__||_BOUT__))
+_fi__(_GENERIC__||!_H8__)
+_if__(_GENERIC__ || !_A29K__)
+@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.
+_fi__(_GENERIC__ || !_A29K__)
+
+_if__(_A29K__)
+@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{_MACH_DEP__}.
+@end quotation
+_fi__(_A29K__)
+
+_if__(_GENERIC__||!_H8__)
+_if__(_AOUT__||_BOUT__||_COFF__)
+_if__(_COFF__||_BOUT__)
+@node Stab, Tag, Space, Pseudo Ops
+_fi__(_COFF__||_BOUT__)
+_if__(!(_COFF__||_BOUT__))
+@node Stab, Text, Space, Pseudo Ops
+_fi__(!(_COFF__||_BOUT__))
+@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
+_fi__(_AOUT__||_BOUT__||_COFF__)
+_fi__(_GENERIC__||!_H8__)
+
+_if__(_COFF__||_BOUT__)
+_if__(_GENERIC__||!_H8__)
+@node Tag, Text, Stab, Pseudo Ops
+_fi__(_GENERIC__||!_H8__)
+_if__(_H8__&&!_GENERIC__)
+@node Tag, Text, Space, Pseudo Ops
+_fi__(_H8__&&!_GENERIC__)
+@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.
+_if__(_BOUT__)
+
+@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.
+_fi__(_BOUT__)
+_fi__(_COFF__||_BOUT__)
+
+_if__(_COFF__||_BOUT__)
+@node Text, Title, Tag, Pseudo Ops
+_fi__(_COFF__||_BOUT__)
+_if__(!(_COFF__||_BOUT__))
+@node Text, Title, Stab, Pseudo Ops
+_fi__(!(_COFF__||_BOUT__))
+@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.
+
+_if__(_COFF__||_BOUT__)
+@node Title, Type, Text, Pseudo Ops
+_fi__(_COFF__||_BOUT__)
+_if__(!(_COFF__||_BOUT__))
+@node Title, Word, Text, Pseudo Ops
+_fi__(!(_COFF__||_BOUT__))
+@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.
+
+_if__(_COFF__||_BOUT__)
+@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.
+_if__(_BOUT__)
+
+@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.
+_fi__(_BOUT__)
+_fi__(_COFF__||_BOUT__)
+
+_if__(_COFF__||_BOUT__)
+@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.
+_if__(_BOUT__)
+
+@samp{.val} is used only for COFF output; when @code{_AS__} is
+configured for @code{b.out}, it accepts this directive but ignores it.
+_fi__(_BOUT__)
+_fi__(_COFF__||_BOUT__)
+
+_if__(_COFF__||_BOUT__)
+@node Word, Deprecated, Val, Pseudo Ops
+_fi__(_COFF__||_BOUT__)
+_if__(!(_COFF__||_BOUT__))
+@node Word, Deprecated, Text, Pseudo Ops
+_fi__(!(_COFF__||_BOUT__))
+@section @code{.word @var{expressions}}
+
+@cindex @code{word} directive
+This directive expects zero or more @var{expressions}, of any section,
+separated by commas.
+_if__((!_GENERIC__) && _W32__)
+For each expression, @code{_AS__} emits a 32-bit number.
+_fi__((!_GENERIC__) && _W32__)
+_if__((!_GENERIC__) && _W16__)
+For each expression, @code{_AS__} emits a 16-bit number.
+_fi__((!_GENERIC__) && _W16__)
+
+_if__(_GENERIC__)
+The size of the number emitted, and its byte order,
+depends on what kind of computer will run the program.
+_fi__(_GENERIC__)
+
+@c on amd29k, i960, sparc the "special treatment to support compilers" doesn't
+@c happen---32-bit addressability, period; no long/short jumps.
+_if__(_GENERIC__ || _DIFFTABKLUG__)
+@cindex difference tables altered
+@cindex altered difference tables
+@quotation
+@emph{Warning: Special Treatment to support Compilers}
+@end quotation
+
+_if__(_GENERIC__)
+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{_MACH_DEP__}), you can ignore this issue.
+
+_fi__(_GENERIC__)
+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.
+
+_if__(_INTERNALS__)
+@emph{This feature may be disabled by compiling @code{_AS__} with the
+@samp{-DWORKING_DOT_WORD} option.} This feature is likely to confuse
+assembly language programmers.
+_fi__(_INTERNALS__)
+_fi__(_GENERIC__ || _DIFFTABKLUG__)
+
+@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 _MACH_DEP__, Copying, Pseudo Ops, Top
+_if__(_GENERIC__)
+@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
+_if__(_VAX__)
+* Vax-Dependent:: VAX Dependent Features
+_fi__(_VAX__)
+_if__(_A29K__)
+* AMD29K-Dependent:: AMD 29K Dependent Features
+_fi__(_A29K__)
+_if__(_H8__)
+* H8/300-Dependent:: AMD 29K Dependent Features
+_fi__(_H8__)
+_if__(_I960__)
+* i960-Dependent:: Intel 80960 Dependent Features
+_fi__(_I960__)
+_if__(_M680X0__)
+* M68K-Dependent:: M680x0 Dependent Features
+_fi__(_M680X0__)
+_if__(_SPARC__)
+* Sparc-Dependent:: SPARC Dependent Features
+_fi__(_SPARC__)
+_if__(_I80386__)
+* i386-Dependent:: 80386 Dependent Features
+_fi__(_I80386__)
+@end menu
+
+_fi__(_GENERIC__)
+_if__(_VAX__)
+_if__(_GENERIC__)
+@node Vax-Dependent, AMD29K-Dependent, Machine Dependent, Machine Dependent
+_fi__(_GENERIC__)
+_CHAPSEC__(0+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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.
+
+_fi__(_VAX__)
+_if__(_A29K__)
+_if__(_GENERIC__)
+@node AMD29K-Dependent, H8/300-Dependent, Vax-Dependent, Machine Dependent
+_fi__(_GENERIC__)
+_CHAPSEC__(0+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) Syntax
+@menu
+* AMD29K-Chars:: Special Characters
+* AMD29K-Regs:: Register Names
+@end menu
+
+@node AMD29K-Chars, AMD29K-Regs, AMD29K Syntax, AMD29K Syntax
+_CHAPSEC__(2+_GENERIC__) 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
+_CHAPSEC__(2+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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.
+
+_fi__(_A29K__)
+_if__(_H8__)
+_if__(_GENERIC__)
+@node H8/300-Dependent, i960-Dependent, AMD29K-Dependent, Machine Dependent
+_fi__(_GENERIC__)
+_CHAPSEC__(0+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(2+_GENERIC__) 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
+_CHAPSEC__(2+_GENERIC__) 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
+_CHAPSEC__(2+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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.
+
+_fi__(_H8__)
+_if__(_I960__)
+_if__(_GENERIC__)
+@node i960-Dependent, M68K-Dependent, H8/300-Dependent, Machine Dependent
+_fi__(_GENERIC__)
+_CHAPSEC__(0+_GENERIC__) 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
+
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(2+_GENERIC__) @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
+_CHAPSEC__(2+_GENERIC__) 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
+_fi__(_I960__)
+
+_if__(_M680X0__)
+_if__(_GENERIC__)
+@c FIXME! node conds are only sufficient for m68k alone, all, and vintage
+_if__(_I960__)
+@node M68K-Dependent, Sparc-Dependent, i960-Dependent, Machine Dependent
+_fi__(_I960__)
+_if__(!_I960__)
+@node M68K-Dependent, Sparc-Dependent, Machine Dependent, Machine Dependent
+_fi__(!_I960__)
+_fi__(_GENERIC__)
+_CHAPSEC__(0+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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}.
+
+_if__(_INTERNALS__)
+If @code{_AS__} is compiled with SUN_ASM_SYNTAX defined, it will also allow
+Sun-style local labels of the form @samp{1$} through @samp{$9}.
+_fi__(_INTERNALS__)
+
+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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(2+_GENERIC__) 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
+_CHAPSEC__(2+_GENERIC__) 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.
+
+_fi__(_M680X0__)
+_if__(0)
+@c pesch@cygnus.com: conditionalize on something other than 0 when filled in.
+@section 32x32
+@section Options
+The 32x32 version of @code{_AS__} accepts a @kbd{-m32032} option to
+specify thiat it is compiling for a 32032 processor, or a
+@kbd{-m32532} to specify that it is compiling for a 32532 option.
+The default (if neither is specified) is chosen when the assembler
+is compiled.
+
+@subsection Syntax
+I don't know anything about the 32x32 syntax assembled by
+@code{_AS__}. Someone who undersands the processor (I've never seen
+one) and the possible syntaxes should write this section.
+
+@subsection Floating Point
+The 32x32 uses @sc{ieee} floating point numbers, but @code{_AS__} will only
+create single or double precision values. I don't know if the 32x32
+understands extended precision numbers.
+
+@subsection 32x32 Machine Directives
+The 32x32 has no machine dependent directives.
+
+_fi__(0)
+_if__(_SPARC__)
+_if__(_GENERIC__)
+_if__(_I80386__&&_M680X0__)
+@node Sparc-Dependent, i386-Dependent, M68K-Dependent, Machine Dependent
+_fi__(_I80386__&&_M680X0__)
+_if__(_I80386__&&_I960__&&!_M680X0__)
+@node Sparc-Dependent, i386-Dependent, i960-Dependent, Machine Dependent
+_fi__(_I80386__&&_I960__&&!_M680X0__)
+_if__(_I80386__&&_A29K__&&(!_I960__)&&!_M680X0__)
+@node Sparc-Dependent, i386-Dependent, AMD29K-Dependent, Machine Dependent
+_fi__(_I80386__&&_A29K__&&(!_I960__)&&!_M680X0__)
+_if__(_I80386__&&_VAX__&&(!_A29K__)&&(!_I960__)&&!_M680X0__)
+@node Sparc-Dependent, i386-Dependent, Vax-Dependent, Machine Dependent
+_fi__(_I80386__&&_VAX__&&(!_A29K__)&&(!_I960__)&&!_M680X0__)
+_if__(_I80386__&&(!_VAX__)&&(!_A29K__)&&(!_I960__)&&!_M680X0__)
+@node Sparc-Dependent, i386-Dependent, Machine Dependent, Machine Dependent
+_fi__(_I80386__&&(!_VAX__)&&(!_A29K__)&&(!_I960__)&&!_M680X0__)
+_if__((!_I80386__)&&_M680X0__)
+@node Sparc-Dependent, , M68K-Dependent, Machine Dependent
+_fi__((!_I80386__)&&_M680X0__)
+_if__((!_I80386__)&&_I960__&&!_M680X0__)
+@node Sparc-Dependent, , i960-Dependent, Machine Dependent
+_fi__((!_I80386__)&&_I960__&&!_M680X0__)
+_if__((!_I80386__)&&_A29K__&&(!_I960__)&&!_M680X0__)
+@node Sparc-Dependent, , AMD29K-Dependent, Machine Dependent
+_fi__((!_I80386__)&&_A29K__&&(!_I960__)&&!_M680X0__)
+_if__((!_I80386__)&&_VAX__&&(!_A29K__)&&(!_I960__)&&!_M680X0__)
+@node Sparc-Dependent, , Vax-Dependent, Machine Dependent
+_fi__((!_I80386__)&&_VAX__&&(!_A29K__)&&(!_I960__)&&!_M680X0__)
+_if__((!_I80386__)&&(!_VAX__)&&(!_A29K__)&&(!_I960__)&&!_M680X0__)
+@node Sparc-Dependent, , Machine Dependent, Machine Dependent
+_fi__((!_I80386__)&&(!_VAX__)&&(!_A29K__)&&(!_I960__)&&!_M680X0__)
+_fi__(_GENERIC__)
+_CHAPSEC__(0+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+
+_fi__(_SPARC__)
+_if__(_I80386__)
+_if__(_GENERIC__)
+@c FIXME! Conditionalize for all combinations in this section
+@node i386-Dependent, , Sparc-Dependent, Machine Dependent
+_fi__(_GENERIC__)
+_CHAPSEC__(0+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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
+_CHAPSEC__(1+_GENERIC__) 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}.
+
+_fi__(_I80386__)
+_if__(0)
+@c pesch@cygnus.com: we ignore the following chapters, since internals are
+@c changing rapidly. These may need to be moved to another
+@c book anyhow, if we adopt the model of user/modifier
+@c books.
+@node Maintenance, Retargeting, _MACH_DEP__, Top
+@chapter Maintaining the Assembler
+[[this chapter is still being built]]
+
+@section Design
+We had these goals, in descending priority:
+@table @b
+@item Accuracy.
+For every program composed by a compiler, @code{_AS__} should emit
+``correct'' code. This leaves some latitude in choosing addressing
+modes, order of @code{relocation_info} structures in the object
+file, @emph{etc}.
+
+@item Speed, for usual case.
+By far the most common use of @code{_AS__} will be assembling compiler
+emissions.
+
+@item Upward compatibility for existing assembler code.
+Well @dots{} we don't support Vax bit fields but everything else
+seems to be upward compatible.
+
+@item Readability.
+The code should be maintainable with few surprises. (JF: ha!)
+
+@end table
+
+We assumed that disk I/O was slow and expensive while memory was
+fast and access to memory was cheap. We expect the in-memory data
+structures to be less than 10 times the size of the emitted object
+file. (Contrast this with the C compiler where in-memory structures
+might be 100 times object file size!)
+This suggests:
+@itemize @bullet
+@item
+Try to read the source file from disk only one time. For other
+reasons, we keep large chunks of the source file in memory during
+assembly so this is not a problem. Also the assembly algorithm
+should only scan the source text once if the compiler composed the
+text according to a few simple rules.
+@item
+Emit the object code bytes only once. Don't store values and then
+backpatch later.
+@item
+Build the object file in memory and do direct writes to disk of
+large buffers.
+@end itemize
+
+RMS suggested a one-pass algorithm which seems to work well. By not
+parsing text during a second pass considerable time is saved on
+large programs (@emph{e.g.} the sort of C program @code{yacc} would
+emit).
+
+It happened that the data structures needed to emit relocation
+information to the object file were neatly subsumed into the data
+structures that do backpatching of addresses after pass 1.
+
+Many of the functions began life as re-usable modules, loosely
+connected. RMS changed this to gain speed. For example, input
+parsing routines which used to work on pre-sanitized strings now
+must parse raw data. Hence they have to import knowledge of the
+assemblers' comment conventions @emph{etc}.
+
+@section Deprecated Feature(?)s
+We have stopped supporting some features:
+@itemize @bullet
+@item
+@code{.org} statements must have @b{defined} expressions.
+@item
+Vax Bit fields (@kbd{:} operator) are entirely unsupported.
+@end itemize
+
+It might be a good idea to not support these features in a future release:
+@itemize @bullet
+@item
+@kbd{#} should begin a comment, even in column 1.
+@item
+Why support the logical line & file concept any more?
+@item
+Subsections are a good candidate for flushing.
+Depends on which compilers need them I guess.
+@end itemize
+
+@section Bugs, Ideas, Further Work
+Clearly the major improvement is DON'T USE A TEXT-READING
+ASSEMBLER for the back end of a compiler. It is much faster to
+interpret binary gobbledygook from a compiler's tables than to
+ask the compiler to write out human-readable code just so the
+assembler can parse it back to binary.
+
+Assuming you use @code{_AS__} for human written programs: here are
+some ideas:
+@itemize @bullet
+@item
+Document (here) @code{APP}.
+@item
+Take advantage of knowing no spaces except after opcode
+to speed up @code{_AS__}. (Modify @code{app.c} to flush useless spaces:
+only keep space/tabs at begin of line or between 2
+symbols.)
+@item
+Put pointers in this documentation to @file{a.out} documentation.
+@item
+Split the assembler into parts so it can gobble direct binary
+from @emph{e.g.} @code{cc}. It is silly for@code{cc} to compose text
+just so @code{_AS__} can parse it back to binary.
+@item
+Rewrite hash functions: I want a more modular, faster library.
+@item
+Clean up LOTS of code.
+@item
+Include all the non-@file{.c} files in the maintenance chapter.
+@item
+Document flonums.
+@item
+Implement flonum short literals.
+@item
+Change all talk of expression operands to expression quantities,
+or perhaps to expression arguments.
+@item
+Implement pass 2.
+@item
+Whenever a @code{.text} or @code{.data} statement is seen, we close
+of the current frag with an imaginary @code{.fill 0}. This is
+because we only have one obstack for frags, and we can't grow new
+frags for a new subsection, then go back to the old subsection and
+append bytes to the old frag. All this nonsense goes away if we
+give each subsection its own obstack. It makes code simpler in
+about 10 places, but nobody has bothered to do it because C compiler
+output rarely changes subsections (compared to ending frags with
+relaxable addresses, which is common).
+@end itemize
+
+@section Sources
+@c The following files in the @file{_AS__} directory
+@c are symbolic links to other files, of
+@c the same name, in a different directory.
+@c @itemize @bullet
+@c @item
+@c @file{atof_generic.c}
+@c @item
+@c @file{atof_vax.c}
+@c @item
+@c @file{flonum_const.c}
+@c @item
+@c @file{flonum_copy.c}
+@c @item
+@c @file{flonum_get.c}
+@c @item
+@c @file{flonum_multip.c}
+@c @item
+@c @file{flonum_normal.c}
+@c @item
+@c @file{flonum_print.c}
+@c @end itemize
+
+Here is a list of the source files in the @file{_AS__} directory.
+
+@table @file
+@item app.c
+This contains the pre-processing phase, which deletes comments,
+handles whitespace, etc. This was recently re-written, since app
+used to be a separate program, but RMS wanted it to be inline.
+
+@item append.c
+This is a subroutine to append a string to another string returning a
+pointer just after the last @code{char} appended. (JF: All these
+little routines should probably all be put in one file.)
+
+@item as.c
+Here you will find the main program of the assembler @code{_AS__}.
+
+@item expr.c
+This is a branch office of @file{read.c}. This understands
+expressions, arguments. Inside @code{_AS__}, arguments are called
+(expression) @emph{operands}. This is confusing, because we also talk
+(elsewhere) about instruction @emph{operands}. Also, expression
+operands are called @emph{quantities} explicitly to avoid confusion
+with instruction operands. What a mess.
+
+@item frags.c
+This implements the @b{frag} concept. Without frags, finding the
+right size for branch instructions would be a lot harder.
+
+@item hash.c
+This contains the symbol table, opcode table @emph{etc.} hashing
+functions.
+
+@item hex_value.c
+This is a table of values of digits, for use in atoi() type
+functions. Could probably be flushed by using calls to strtol(), or
+something similar.
+
+@item input-file.c
+This contains Operating system dependent source file reading
+routines. Since error messages often say where we are in reading
+the source file, they live here too. Since @code{_AS__} is intended to
+run under GNU and Unix only, this might be worth flushing. Anyway,
+almost all C compilers support stdio.
+
+@item input-scrub.c
+This deals with calling the pre-processor (if needed) and feeding the
+chunks back to the rest of the assembler the right way.
+
+@item messages.c
+This contains operating system independent parts of fatal and
+warning message reporting. See @file{append.c} above.
+
+@item output-file.c
+This contains operating system dependent functions that write an
+object file for @code{_AS__}. See @file{input-file.c} above.
+
+@item read.c
+This implements all the directives of @code{_AS__}. This also deals
+with passing input lines to the machine dependent part of the
+assembler.
+
+@item strstr.c
+This is a C library function that isn't in most C libraries yet.
+See @file{append.c} above.
+
+@item subsegs.c
+This implements subsections.
+
+@item symbols.c
+This implements symbols.
+
+@item write.c
+This contains the code to perform relaxation, and to write out
+the object file. It is mostly operating system independent, but
+different OSes have different object file formats in any case.
+
+@item xmalloc.c
+This implements @code{malloc()} or bust. See @file{append.c} above.
+
+@item xrealloc.c
+This implements @code{realloc()} or bust. See @file{append.c} above.
+
+@item atof-generic.c
+The following files were taken from a machine-independent subroutine
+library for manipulating floating point numbers and very large
+integers.
+
+@file{atof-generic.c} turns a string into a flonum internal format
+floating-point number.
+
+@item flonum-const.c
+This contains some potentially useful floating point numbers in
+flonum format.
+
+@item flonum-copy.c
+This copies a flonum.
+
+@item flonum-multip.c
+This multiplies two flonums together.
+
+@item bignum-copy.c
+This copies a bignum.
+
+@end table
+
+Here is a table of all the machine-specific files (this includes
+both source and header files). Typically, there is a
+@var{machine}.c file, a @var{machine}-opcode.h file, and an
+atof-@var{machine}.c file. The @var{machine}-opcode.h file should
+be identical to the one used by GDB (which uses it for disassembly.)
+
+@table @file
+
+@item atof-ieee.c
+This contains code to turn a flonum into a ieee literal constant.
+This is used by tye 680x0, 32x32, sparc, and i386 versions of @code{_AS__}.
+
+@item i386-opcode.h
+This is the opcode-table for the i386 version of the assembler.
+
+@item i386.c
+This contains all the code for the i386 version of the assembler.
+
+@item i386.h
+This defines constants and macros used by the i386 version of the assembler.
+
+@item m-generic.h
+generic 68020 header file. To be linked to m68k.h on a
+non-sun3, non-hpux system.
+
+@item m-sun2.h
+68010 header file for Sun2 workstations. Not well tested. To be linked
+to m68k.h on a sun2. (See also @samp{-DSUN_ASM_SYNTAX} in the
+@file{Makefile}.)
+
+@item m-sun3.h
+68020 header file for Sun3 workstations. To be linked to m68k.h before
+compiling on a Sun3 system. (See also @samp{-DSUN_ASM_SYNTAX} in the
+@file{Makefile}.)
+
+@item m-hpux.h
+68020 header file for a HPUX (system 5?) box. Which box, which
+version of HPUX, etc? I don't know.
+
+@item m68k.h
+A hard- or symbolic- link to one of @file{m-generic.h},
+@file{m-hpux.h} or @file{m-sun3.h} depending on which kind of
+680x0 you are assembling for. (See also @samp{-DSUN_ASM_SYNTAX} in the
+@file{Makefile}.)
+
+@item m68k-opcode.h
+Opcode table for 68020. This is now a link to the opcode table
+in the @code{GDB} source directory.
+
+@item m68k.c
+All the mc680x0 code, in one huge, slow-to-compile file.
+
+@item ns32k.c
+This contains the code for the ns32032/ns32532 version of the
+assembler.
+
+@item ns32k-opcode.h
+This contains the opcode table for the ns32032/ns32532 version
+of the assembler.
+
+@item vax-inst.h
+Vax specific file for describing Vax operands and other Vax-ish things.
+
+@item vax-opcode.h
+Vax opcode table.
+
+@item vax.c
+Vax specific parts of @code{_AS__}. Also includes the former files
+@file{vax-ins-parse.c}, @file{vax-reg-parse.c} and @file{vip-op.c}.
+
+@item atof-vax.c
+Turns a flonum into a Vax constant.
+
+@item vms.c
+This file contains the special code needed to put out a VMS
+style object file for the Vax.
+
+@end table
+
+Here is a list of the header files in the source directory.
+(Warning: This section may not be very accurate. I didn't
+write the header files; I just report them.) Also note that I
+think many of these header files could be cleaned up or
+eliminated.
+
+@table @file
+
+@item a.out.h
+This describes the structures used to create the binary header data
+inside the object file. Perhaps we should use the one in
+@file{/usr/include}?
+
+@item as.h
+This defines all the globally useful things, and pulls in _0__<stdio.h>_1__
+and _0__<assert.h>_1__.
+
+@item bignum.h
+This defines macros useful for dealing with bignums.
+
+@item expr.h
+Structure and macros for dealing with expression()
+
+@item flonum.h
+This defines the structure for dealing with floating point
+numbers. It #includes @file{bignum.h}.
+
+@item frags.h
+This contains macro for appending a byte to the current frag.
+
+@item hash.h
+Structures and function definitions for the hashing functions.
+
+@item input-file.h
+Function headers for the input-file.c functions.
+
+@item md.h
+structures and function headers for things defined in the
+machine dependent part of the assembler.
+
+@item obstack.h
+This is the GNU systemwide include file for manipulating obstacks.
+Since nobody is running under real GNU yet, we include this file.
+
+@item read.h
+Macros and function headers for reading in source files.
+
+@item struct-symbol.h
+Structure definition and macros for dealing with the _AS__
+internal form of a symbol.
+
+@item subsegs.h
+structure definition for dealing with the numbered subsections
+of the text and data sections.
+
+@item symbols.h
+Macros and function headers for dealing with symbols.
+
+@item write.h
+Structure for doing section fixups.
+@end table
+
+@comment ~subsection Test Directory
+@comment (Note: The test directory seems to have disappeared somewhere
+@comment along the line. If you want it, you'll probably have to find a
+@comment REALLY OLD dump tape~dots{})
+@comment
+@comment The ~file{test/} directory is used for regression testing.
+@comment After you modify ~@code{_AS__}, you can get a quick go/nogo
+@comment confidence test by running the new ~@code{_AS__} over the source
+@comment files in this directory. You use a shell script ~file{test/do}.
+@comment
+@comment The tests in this suite are evolving. They are not comprehensive.
+@comment They have, however, caught hundreds of bugs early in the debugging
+@comment cycle of ~@code{_AS__}. Most test statements in this suite were naturally
+@comment selected: they were used to demonstrate actual ~@code{_AS__} bugs rather
+@comment than being written ~i{a prioi}.
+@comment
+@comment Another testing suggestion: over 30 bugs have been found simply by
+@comment running examples from this manual through ~@code{_AS__}.
+@comment Some examples in this manual are selected
+@comment to distinguish boundary conditions; they are good for testing ~@code{_AS__}.
+@comment
+@comment ~subsubsection Regression Testing
+@comment Each regression test involves assembling a file and comparing the
+@comment actual output of ~@code{_AS__} to ``known good'' output files. Both
+@comment the object file and the error/warning message file (stderr) are
+@comment inspected. Optionally the ~@code{_AS__} exit status may be checked.
+@comment Discrepencies are reported. Each discrepency means either that
+@comment you broke some part of ~@code{_AS__} or that the ``known good'' files
+@comment are now out of date and should be changed to reflect the new
+@comment definition of ``good''.
+@comment
+@comment Each regression test lives in its own directory, in a tree
+@comment rooted in the directory ~file{test/}. Each such directory
+@comment has a name ending in ~file{.ret}, where `ret' stands for
+@comment REgression Test. The ~file{.ret} ending allows ~code{find
+@comment (1)} to find all regression tests in the tree, without
+@comment needing to list them explicitly.
+@comment
+@comment Any ~file{.ret} directory must contain a file called
+@comment ~file{input} which is the source file to assemble. During
+@comment testing an object file ~file{output} is created, as well as
+@comment a file ~file{stdouterr} which contains the output to both
+@comment stderr and stderr. If there is a file ~file{output.good} in
+@comment the directory, and if ~file{output} contains exactly the
+@comment same data as ~file{output.good}, the file ~file{output} is
+@comment deleted. Likewise ~file{stdouterr} is removed if it exactly
+@comment matches a file ~file{stdouterr.good}. If file
+@comment ~file{status.good} is present, containing a decimal number
+@comment before a newline, the exit status of ~@code{_AS__} is compared
+@comment to this number. If the status numbers are not equal, a file
+@comment ~file{status} is written to the directory, containing the
+@comment actual status as a decimal number followed by newline.
+@comment
+@comment Should any of the ~file{*.good} files fail to match their corresponding
+@comment actual files, this is noted by a 1-line message on the screen during
+@comment the regression test, and you can use ~@code{find (1)} to find any
+@comment files named ~file{status}, ~file {output} or ~file{stdouterr}.
+@comment
+@node Retargeting, Copying, Maintenance, Top
+@chapter Teaching the Assembler about a New Machine
+
+This chapter describes the steps required in order to make the
+assembler work with another machine's assembly language. This
+chapter is not complete, and only describes the steps in the
+broadest terms. You should look at the source for the
+currently supported machine in order to discover some of the
+details that aren't mentioned here.
+
+You should create a new file called @file{@var{machine}.c}, and
+add the appropriate lines to the file @file{Makefile} so that
+you can compile your new version of the assembler. This should
+be straighforward; simply add lines similar to the ones there
+for the four current versions of the assembler.
+
+If you want to be compatible with GDB, (and the current
+machine-dependent versions of the assembler), you should create
+a file called @file{@var{machine}-opcode.h} which should
+contain all the information about the names of the machine
+instructions, their opcodes, and what addressing modes they
+support. If you do this right, the assembler and GDB can share
+this file, and you'll only have to write it once. Note that
+while you're writing @code{_AS__}, you may want to use an
+independent program (if you have access to one), to make sure
+that @code{_AS__} is emitting the correct bytes. Since @code{_AS__}
+and @code{GDB} share the opcode table, an incorrect opcode
+table entry may make invalid bytes look OK when you disassemble
+them with @code{GDB}.
+
+@section Functions You will Have to Write
+
+Your file @file{@var{machine}.c} should contain definitions for
+the following functions and variables. It will need to include
+some header files in order to use some of the structures
+defined in the machine-independent part of the assembler. The
+needed header files are mentioned in the descriptions of the
+functions that will need them.
+
+@table @code
+
+@item long omagic;
+This long integer holds the value to place at the beginning of
+the @file{a.out} file. It is usually @samp{OMAGIC}, except on
+machines that store additional information in the magic-number.
+
+@item char comment_chars[];
+This character array holds the values of the characters that
+start a comment anywhere in a line. Comments are stripped off
+automatically by the machine independent part of the
+assembler. Note that the @samp{/*} will always start a
+comment, and that only @samp{*/} will end a comment started by
+@samp{*/}.
+
+@item char line_comment_chars[];
+This character array holds the values of the chars that start a
+comment only if they are the first (non-whitespace) character
+on a line. If the character @samp{#} does not appear in this
+list, you may get unexpected results. (Various
+machine-independent parts of the assembler treat the comments
+@samp{#APP} and @samp{#NO_APP} specially, and assume that lines
+that start with @samp{#} are comments.)
+
+@item char EXP_CHARS[];
+This character array holds the letters that can separate the
+mantissa and the exponent of a floating point number. Typical
+values are @samp{e} and @samp{E}.
+
+@item char FLT_CHARS[];
+This character array holds the letters that--when they appear
+immediately after a leading zero--indicate that a number is a
+floating-point number. (Sort of how 0x indicates that a
+hexadecimal number follows.)
+
+@item pseudo_typeS md_pseudo_table[];
+(@var{pseudo_typeS} is defined in @file{md.h})
+This array contains a list of the machine_dependent directives
+the assembler must support. It contains the name of each
+pseudo op (Without the leading @samp{.}), a pointer to a
+function to be called when that directive is encountered, and
+an integer argument to be passed to that function.
+
+@item void md_begin(void)
+This function is called as part of the assembler's
+initialization. It should do any initialization required by
+any of your other routines.
+
+@item int md_parse_option(char **optionPTR, int *argcPTR, char ***argvPTR)
+This routine is called once for each option on the command line
+that the machine-independent part of @code{_AS__} does not
+understand. This function should return non-zero if the option
+pointed to by @var{optionPTR} is a valid option. If it is not
+a valid option, this routine should return zero. The variables
+@var{argcPTR} and @var{argvPTR} are provided in case the option
+requires a filename or something similar as an argument. If
+the option is multi-character, @var{optionPTR} should be
+advanced past the end of the option, otherwise every letter in
+the option will be treated as a separate single-character
+option.
+
+@item void md_assemble(char *string)
+This routine is called for every machine-dependent
+non-directive line in the source file. It does all the real
+work involved in reading the opcode, parsing the operands,
+etc. @var{string} is a pointer to a null-terminated string,
+that comprises the input line, with all excess whitespace and
+comments removed.
+
+@item void md_number_to_chars(char *outputPTR,long value,int nbytes)
+This routine is called to turn a C long int, short int, or char
+into the series of bytes that represents that number on the
+target machine. @var{outputPTR} points to an array where the
+result should be stored; @var{value} is the value to store; and
+@var{nbytes} is the number of bytes in 'value' that should be
+stored.
+
+@item void md_number_to_imm(char *outputPTR,long value,int nbytes)
+This routine is called to turn a C long int, short int, or char
+into the series of bytes that represent an immediate value on
+the target machine. It is identical to the function @code{md_number_to_chars},
+except on NS32K machines.@refill
+
+@item void md_number_to_disp(char *outputPTR,long value,int nbytes)
+This routine is called to turn a C long int, short int, or char
+into the series of bytes that represent an displacement value on
+the target machine. It is identical to the function @code{md_number_to_chars},
+except on NS32K machines.@refill
+
+@item void md_number_to_field(char *outputPTR,long value,int nbytes)
+This routine is identical to @code{md_number_to_chars},
+except on NS32K machines.
+
+@item void md_ri_to_chars(struct relocation_info *riPTR,ri)
+(@code{struct relocation_info} is defined in @file{a.out.h})
+This routine emits the relocation info in @var{ri}
+in the appropriate bit-pattern for the target machine.
+The result should be stored in the location pointed
+to by @var{riPTR}. This routine may be a no-op unless you are
+attempting to do cross-assembly.
+
+@item char *md_atof(char type,char *outputPTR,int *sizePTR)
+This routine turns a series of digits into the appropriate
+internal representation for a floating-point number.
+@var{type} is a character from @var{FLT_CHARS[]} that describes
+what kind of floating point number is wanted; @var{outputPTR}
+is a pointer to an array that the result should be stored in;
+and @var{sizePTR} is a pointer to an integer where the size (in
+bytes) of the result should be stored. This routine should
+return an error message, or an empty string (not (char *)0) for
+success.
+
+@item int md_short_jump_size;
+This variable holds the (maximum) size in bytes of a short (16
+bit or so) jump created by @code{md_create_short_jump()}. This
+variable is used as part of the broken-word feature, and isn't
+needed if the assembler is compiled with
+@samp{-DWORKING_DOT_WORD}.
+
+@item int md_long_jump_size;
+This variable holds the (maximum) size in bytes of a long (32
+bit or so) jump created by @code{md_create_long_jump()}. This
+variable is used as part of the broken-word feature, and isn't
+needed if the assembler is compiled with
+@samp{-DWORKING_DOT_WORD}.
+
+@item void md_create_short_jump(char *resultPTR,long from_addr,
+@code{long to_addr,fragS *frag,symbolS *to_symbol)}
+This function emits a jump from @var{from_addr} to @var{to_addr} in
+the array of bytes pointed to by @var{resultPTR}. If this creates a
+type of jump that must be relocated, this function should call
+@code{fix_new()} with @var{frag} and @var{to_symbol}. The jump
+emitted by this function may be smaller than @var{md_short_jump_size},
+but it must never create a larger one.
+(If it creates a smaller jump, the extra bytes of memory will not be
+used.) This function is used as part of the broken-word feature,
+and isn't needed if the assembler is compiled with
+@samp{-DWORKING_DOT_WORD}.@refill
+
+@item void md_create_long_jump(char *ptr,long from_addr,
+@code{long to_addr,fragS *frag,symbolS *to_symbol)}
+This function is similar to the previous function,
+@code{md_create_short_jump()}, except that it creates a long
+jump instead of a short one. This function is used as part of
+the broken-word feature, and isn't needed if the assembler is
+compiled with @samp{-DWORKING_DOT_WORD}.
+
+@item int md_estimate_size_before_relax(fragS *fragPTR,int segment_type)
+This function does the initial setting up for relaxation. This
+includes forcing references to still-undefined symbols to the
+appropriate addressing modes.
+
+@item relax_typeS md_relax_table[];
+(relax_typeS is defined in md.h)
+This array describes the various machine dependent states a
+frag may be in before relaxation. You will need one group of
+entries for each type of addressing mode you intend to relax.
+
+@item void md_convert_frag(fragS *fragPTR)
+(@var{fragS} is defined in @file{as.h})
+This routine does the required cleanup after relaxation.
+Relaxation has changed the type of the frag to a type that can
+reach its destination. This function should adjust the opcode
+of the frag to use the appropriate addressing mode.
+@var{fragPTR} points to the frag to clean up.
+
+@item void md_end(void)
+This function is called just before the assembler exits. It
+need not free up memory unless the operating system doesn't do
+it automatically on exit. (In which case you'll also have to
+track down all the other places where the assembler allocates
+space but never frees it.)
+
+@end table
+
+@section External Variables You will Need to Use
+
+You will need to refer to or change the following external variables
+from within the machine-dependent part of the assembler.
+
+@table @code
+@item extern char flagseen[];
+This array holds non-zero values in locations corresponding to
+the options that were on the command line. Thus, if the
+assembler was called with @samp{-W}, @var{flagseen['W']} would
+be non-zero.
+
+@item extern fragS *frag_now;
+This pointer points to the current frag--the frag that bytes
+are currently being added to. If nothing else, you will need
+to pass it as an argument to various machine-independent
+functions. It is maintained automatically by the
+frag-manipulating functions; you should never have to change it
+yourself.
+
+@item extern LITTLENUM_TYPE generic_bignum[];
+(@var{LITTLENUM_TYPE} is defined in @file{bignum.h}.
+This is where @dfn{bignums}--numbers larger than 32 bits--are
+returned when they are encountered in an expression. You will
+need to use this if you need to implement directives (or
+anything else) that must deal with these large numbers.
+@code{Bignums} are of @code{segT} @code{SEG_BIG} (defined in
+@file{as.h}, and have a positive @code{X_add_number}. The
+@code{X_add_number} of a @code{bignum} is the number of
+@code{LITTLENUMS} in @var{generic_bignum} that the number takes
+up.
+
+@item extern FLONUM_TYPE generic_floating_point_number;
+(@var{FLONUM_TYPE} is defined in @file{flonum.h}.
+The is where @dfn{flonums}--floating-point numbers within
+expressions--are returned. @code{Flonums} are of @code{segT}
+@code{SEG_BIG}, and have a negative @code{X_add_number}.
+@code{Flonums} are returned in a generic format. You will have
+to write a routine to turn this generic format into the
+appropriate floating-point format for your machine.
+
+@item extern int need_pass_2;
+If this variable is non-zero, the assembler has encountered an
+expression that cannot be assembled in a single pass. Since
+the second pass isn't implemented, this flag means that the
+assembler is punting, and is only looking for additional syntax
+errors. (Or something like that.)
+
+@item extern segT now_seg;
+This variable holds the value of the section the assembler is
+currently assembling into.
+
+@end table
+
+@section External functions will you need
+
+You will find the following external functions useful (or
+indispensable) when you're writing the machine-dependent part
+of the assembler.
+
+@table @code
+
+@item char *frag_more(int bytes)
+This function allocates @var{bytes} more bytes in the current
+frag (or starts a new frag, if it can't expand the current frag
+any more.) for you to store some object-file bytes in. It
+returns a pointer to the bytes, ready for you to store data in.
+
+@item void fix_new(fragS *frag, int where, short size, symbolS *add_symbol, symbolS *sub_symbol, long offset, int pcrel)
+This function stores a relocation fixup to be acted on later.
+@var{frag} points to the frag the relocation belongs in;
+@var{where} is the location within the frag where the relocation begins;
+@var{size} is the size of the relocation, and is usually 1 (a single byte),
+ 2 (sixteen bits), or 4 (a longword).
+The value @var{add_symbol} @minus{} @var{sub_symbol} + @var{offset}, is added to the byte(s)
+at _0__@var{frag->literal[where]}_1__. If @var{pcrel} is non-zero, the address of the
+location is subtracted from the result. A relocation entry is also added
+to the @file{a.out} file. @var{add_symbol}, @var{sub_symbol}, and/or
+@var{offset} may be NULL.@refill
+
+@item char *frag_var(relax_stateT type, int max_chars, int var,
+@code{relax_substateT subtype, symbolS *symbol, char *opcode)}
+This function creates a machine-dependent frag of type @var{type}
+(usually @code{rs_machine_dependent}).
+@var{max_chars} is the maximum size in bytes that the frag may grow by;
+@var{var} is the current size of the variable end of the frag;
+@var{subtype} is the sub-type of the frag. The sub-type is used to index into
+@var{md_relax_table[]} during @code{relaxation}.
+@var{symbol} is the symbol whose value should be used to when relax-ing this frag.
+@var{opcode} points into a byte whose value may have to be modified if the
+addressing mode used by this frag changes. It typically points into the
+@var{fr_literal[]} of the previous frag, and is used to point to a location
+that @code{md_convert_frag()}, may have to change.@refill
+
+@item void frag_wane(fragS *fragPTR)
+This function is useful from within @code{md_convert_frag}. It
+changes a frag to type rs_fill, and sets the variable-sized
+piece of the frag to zero. The frag will never change in size
+again.
+
+@item segT expression(expressionS *retval)
+(@var{segT} is defined in @file{as.h}; @var{expressionS} is defined in @file{expr.h})
+This function parses the string pointed to by the external char
+pointer @var{input_line_pointer}, and returns the section-type
+of the expression. It also stores the results in the
+@var{expressionS} pointed to by @var{retval}.
+@var{input_line_pointer} is advanced to point past the end of
+the expression. (@var{input_line_pointer} is used by other
+parts of the assembler. If you modify it, be sure to restore
+it to its original value.)
+
+@item as_warn(char *message,@dots{})
+If warning messages are disabled, this function does nothing.
+Otherwise, it prints out the current file name, and the current
+line number, then uses @code{fprintf} to print the
+@var{message} and any arguments it was passed.
+
+@item as_bad(char *message,@dots{})
+This function should be called when @code{_AS__} encounters
+conditions that are bad enough that @code{_AS__} should not
+produce an object file, but should continue reading input and
+printing warning and bad error messages.
+
+@item as_fatal(char *message,@dots{})
+This function prints out the current file name and line number,
+prints the word @samp{FATAL:}, then uses @code{fprintf} to
+print the @var{message} and any arguments it was passed. Then
+the assembler exits. This function should only be used for
+serious, unrecoverable errors.
+
+@item void float_const(int float_type)
+This function reads floating-point constants from the current
+input line, and calls @code{md_atof} to assemble them. It is
+useful as the function to call for the directives
+@samp{.single}, @samp{.double}, @samp{.float}, etc.
+@var{float_type} must be a character from @var{FLT_CHARS}.
+
+@item void demand_empty_rest_of_line(void);
+This function can be used by machine-dependent directives to
+make sure the rest of the input line is empty. It prints a
+warning message if there are additional characters on the line.
+
+@item long int get_absolute_expression(void)
+This function can be used by machine-dependent directives to
+read an absolute number from the current input line. It
+returns the result. If it isn't given an absolute expression,
+it prints a warning message and returns zero.
+
+@end table
+
+
+@section The concept of Frags
+
+This assembler works to optimize the size of certain addressing
+modes. (e.g. branch instructions) This means the size of many
+pieces of object code cannot be determined until after assembly
+is finished. (This means that the addresses of symbols cannot be
+determined until assembly is finished.) In order to do this,
+@code{_AS__} stores the output bytes as @dfn{frags}.
+
+Here is the definition of a frag (from @file{as.h})
+@smallexample
+struct frag
+@{
+ long int fr_fix;
+ long int fr_var;
+ relax_stateT fr_type;
+ relax_substateT fr_substate;
+ unsigned long fr_address;
+ long int fr_offset;
+ struct symbol *fr_symbol;
+ char *fr_opcode;
+ struct frag *fr_next;
+ char fr_literal[];
+@}
+@end smallexample
+
+@table @var
+@item fr_fix
+is the size of the fixed-size piece of the frag.
+
+@item fr_var
+is the maximum (?) size of the variable-sized piece of the frag.
+
+@item fr_type
+is the type of the frag.
+Current types are:
+rs_fill
+rs_align
+rs_org
+rs_machine_dependent
+
+@item fr_substate
+This stores the type of machine-dependent frag this is. (what
+kind of addressing mode is being used, and what size is being
+tried/will fit/etc.
+
+@item fr_address
+@var{fr_address} is only valid after relaxation is finished.
+Before relaxation, the only way to store an address is (pointer
+to frag containing the address) plus (offset into the frag).
+
+@item fr_offset
+This contains a number, whose meaning depends on the type of
+the frag.
+for machine_dependent frags, this contains the offset from
+fr_symbol that the frag wants to go to. Thus, for branch
+instructions it is usually zero. (unless the instruction was
+@samp{jba foo+12} or something like that.)
+
+@item fr_symbol
+for machine_dependent frags, this points to the symbol the frag
+needs to reach.
+
+@item fr_opcode
+This points to the location in the frag (or in a previous frag)
+of the opcode for the instruction that caused this to be a frag.
+@var{fr_opcode} is needed if the actual opcode must be changed
+in order to use a different form of the addressing mode.
+(For example, if a conditional branch only comes in size tiny,
+a large-size branch could be implemented by reversing the sense
+of the test, and turning it into a tiny branch over a large jump.
+This would require changing the opcode.)
+
+@var{fr_literal} is a variable-size array that contains the
+actual object bytes. A frag consists of a fixed size piece of
+object data, (which may be zero bytes long), followed by a
+piece of object data whose size may not have been determined
+yet. Other information includes the type of the frag (which
+controls how it is relaxed),
+
+@item fr_next
+This is the next frag in the singly-linked list. This is
+usually only needed by the machine-independent part of
+@code{_AS__}.
+
+@end table
+_fi__(0)
+
+@node Copying, Index, _MACH_DEP__, 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/doc/config.status b/gnu/usr.bin/as/doc/config.status
new file mode 100644
index 0000000..f1e7f63
--- /dev/null
+++ b/gnu/usr.bin/as/doc/config.status
@@ -0,0 +1,5 @@
+#!/bin/sh
+# This file was generated automatically by configure. Do not edit.
+# /d/users/pk/src/gnu/usr.bin/gas.1.93/gas/doc was configured as follows:
+/d/users/pk/src/gnu/usr.bin/gas.1.93/./configure i386 -target=i386 -norecursion
+#
diff --git a/gnu/usr.bin/as/doc/configure.in b/gnu/usr.bin/as/doc/configure.in
new file mode 100644
index 0000000..f9820ea
--- /dev/null
+++ b/gnu/usr.bin/as/doc/configure.in
@@ -0,0 +1,34 @@
+# 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=all.m4
+srcname="gas doc"
+
+# per-host:
+
+# per-target:
+
+# end of gas/doc/configure.in
diff --git a/gnu/usr.bin/as/doc/gen.m4 b/gnu/usr.bin/as/doc/gen.m4
new file mode 100644
index 0000000..bf444a6
--- /dev/null
+++ b/gnu/usr.bin/as/doc/gen.m4
@@ -0,0 +1,14 @@
+_divert__(-1)
+<$Id: gen.m4,v 1.1 1993/10/02 21:00:19 pk Exp $>
+_define__(<_GENERIC__>,<1>) In case none.m4 changes its mind abt default
+
+_define__(<_AOUT__>,<1>)
+_define__(<_COFF__>,<1>)
+_define__(<_ELF__>,<1>)
+
+_define__(<_I80386__>,<1>)
+_define__(<_M680X0__>,<1>)
+_define__(<_SPARC__>,<1>)
+_define__(<_VAX__>,<1>)
+
+_divert__<>
diff --git a/gnu/usr.bin/as/doc/h8.m4 b/gnu/usr.bin/as/doc/h8.m4
new file mode 100644
index 0000000..ed52c85
--- /dev/null
+++ b/gnu/usr.bin/as/doc/h8.m4
@@ -0,0 +1,15 @@
+_divert__(-1)
+_define__(<_H8__>,<1>)
+_define__(<_AS__>,<as83>)
+_define__(<_GENERIC__>,<0>)
+_define__(<_HOST__>,<H8/300>)
+_define__(<_MACH_DEP__>,<H8/300-Dependent>)
+_define__(<_AOUT__>,<0>)
+_define__(<_BOUT__>,<0>)
+_define__(<_COFF__>,<1>)
+_define__(<_ELF__>,<0>)
+_define__(<_DIFFTABKLUG__>,0) NO difference-table kluge
+_define__(<_IEEEFLOAT__>,1) IEEE floating point
+_define__(<_W32__>,0)
+_define__(<_W16__>,1) 16-bit words
+_divert__<>
diff --git a/gnu/usr.bin/as/doc/i80386.m4 b/gnu/usr.bin/as/doc/i80386.m4
new file mode 100644
index 0000000..e8718aa
--- /dev/null
+++ b/gnu/usr.bin/as/doc/i80386.m4
@@ -0,0 +1,12 @@
+_divert__(-1)
+_define__(<_I80386__>,<1>)
+_define__(<_GENERIC__>,<0>)
+_define__(<_HOST__>,<Intel 80386>)
+_define__(<_MACH_DEP__>,<i386-Dependent>)
+_define__(<_AOUT__>,<1>)
+_define__(<_BOUT__>,<0>)
+_define__(<_COFF__>,<0>)
+_define__(<_ELF__>,<0>)
+_define__(<_W32__>,0)
+_define__(<_W16__>,1) 16-bit words
+_divert__<>
diff --git a/gnu/usr.bin/as/doc/i960.m4 b/gnu/usr.bin/as/doc/i960.m4
new file mode 100644
index 0000000..1fca147
--- /dev/null
+++ b/gnu/usr.bin/as/doc/i960.m4
@@ -0,0 +1,16 @@
+_divert__(-1)
+_define__(<_I960__>,<1>)
+_define__(<_AOUT__>,<0>)
+_define__(<_BOUT__>,<1>)
+_define__(<_COFF__>,<1>)
+_define__(<_AS__>,<gas960>)
+_define__(<_GCC__>,<gcc960>)
+_define__(<_LD__>,<gld960>)
+_define__(<_GDB__>,<gdb960>)
+_define__(<_HOST__>,<Intel 960>)
+_define__(<_MACH_DEP__>,<i960-Dependent>)
+_define__(<_DIFFTABKLUG__>,0) NO difference-table kluge
+_define__(<_IEEEFLOAT__>,1) IEEE floating point
+_define__(<_W32__>,1) 32-bit words
+_define__(<_W16__>,0)
+_divert__<>
diff --git a/gnu/usr.bin/as/doc/m680x0.m4 b/gnu/usr.bin/as/doc/m680x0.m4
new file mode 100644
index 0000000..4013e72
--- /dev/null
+++ b/gnu/usr.bin/as/doc/m680x0.m4
@@ -0,0 +1,8 @@
+_divert__(-1)
+_define__(<_GENERIC__>,<0>)
+_define__(<_M680X0__>,<1>)
+_define__(<_HOST__>,<Motorola 680x0>)
+_define__(<_MACH_DEP__>,<M68K-Dependent>)
+_define__(<_W32__>,0)
+_define__(<_W16__>,1) 16-bit words
+_divert__<>
diff --git a/gnu/usr.bin/as/doc/none.m4 b/gnu/usr.bin/as/doc/none.m4
new file mode 100644
index 0000000..dfa17d3
--- /dev/null
+++ b/gnu/usr.bin/as/doc/none.m4
@@ -0,0 +1,57 @@
+_divert__(-1)
+<$Id: none.m4,v 1.1 1993/10/02 21:00:24 pk Exp $>
+
+Switches:
+
+_define__(<_ALL_ARCH__>,<0>) (Meant as most inclusive; file turning
+ it on is expected to also turn on
+ all arch-related switches including
+ "_GENERIC__")
+_define__(<_GENERIC__>,<1>) (may not be quite all configs;
+ meant for "most vanilla" manual)
+_define__(<_INTERNALS__>,<0>)
+
+_define__(<_AOUT__>,<1>) Object formats. Note we turn on one.
+_define__(<_BOUT__>,<0>)
+_define__(<_COFF__>,<0>)
+_define__(<_ELF__>,<0>)
+
+ Properties of the assembler
+_define__(<_DIFFTABKLUG__>,1) Do we use the difference-table kluge?
+_define__(<_IEEEFLOAT__>,0) IEEE floating-point?
+_define__(<_W32__>,0) word is 32 bits
+_define__(<_W16__>,1) word is 16 bits
+
+_define__(<_A29K__>,<0>) Specific architectures. Note none
+_define__(<_H8__>,<0>) starts out on.
+_define__(<_I80386__>,<0>)
+_define__(<_I960__>,<0>)
+_define__(<_M680X0__>,<0>)
+_define__(<_SPARC__>,<0>)
+_define__(<_VAX__>,<0>)
+_define__(<_VXWORKS__>,<0>)
+
+Text:
+
+Default names; individual configs may override
+Assembler:
+_define__(<_AS__>,<as>)
+C Compiler:
+_define__(<_GCC__>,<gcc>)
+Linker:
+_define__(<_LD__>,<ld>)
+Debugger name:
+_define__(<_GDBN__>,<GDB>)
+Debugger program:
+_define__(<_GDBP__>,<gdb>)
+Debugger init file:
+_define__(<_GDBINIT__>,<.gdbinit>)
+
+Text for host; individual configs *should* override, but this may
+catch some flubs
+_define__(<_HOST__>,<machine specific>)
+
+"Machine Dependent" nodename
+_define__(<_MACH_DEP__>,<Machine Dependent>)
+
+_divert__<>
diff --git a/gnu/usr.bin/as/doc/pretex.m4 b/gnu/usr.bin/as/doc/pretex.m4
new file mode 100644
index 0000000..9a9696f
--- /dev/null
+++ b/gnu/usr.bin/as/doc/pretex.m4
@@ -0,0 +1,268 @@
+divert(-1) -*-Text-*-
+` Copyright (c) 1991 Free Software Foundation, Inc.'
+` This file defines and documents the M4 macros used '
+` to preprocess some GNU manuals'
+` $Id: pretex.m4,v 1.1 1993/10/02 21:00:25 pk Exp $'
+
+I. INTRODUCTION
+
+This collection of M4 macros is meant to help in pre-processing texinfo
+files to allow configuring them by hosts; for example, the reader of an
+as manual who only has access to a 386 may not really want to see crud about
+VAXen.
+
+A preprocessor is used, rather than extending texinfo, because this
+way we can hack the conditionals in only one place; otherwise we would
+have to write TeX macros, update makeinfo, and update the Emacs
+info-formatting functions.
+
+II. COMPATIBILITY
+
+These macros should work with GNU m4 and System V m4; they do not work
+with Sun or Berkeley M4.
+
+III. USAGE
+
+A. M4 INVOCATION
+Assume this file is called "pretex.m4". Then, to preprocess a
+document "mybook.texinfo" you might do something like the following:
+
+ m4 pretex.m4 none.m4 PARTIC.m4 mybook.texinfo >mybook-PARTIC.texinfo
+
+---where your path is set to find GNU or SysV "m4", and the other m4
+files mentioned are as follows:
+
+ none.m4: A file that defines, as 0, all the options you might
+ want to turn on using the conditionals defined below.
+ Unlike the C preprocessor, m4 does not default
+ undefined macros to 0. For example, here is a "none.m4"
+ I have been using:
+ _divert__(-1)
+
+ _define__(<_ALL_ARCH__>,<0>)
+ _define__(<_INTERNALS__>,<0>)
+
+ _define__(<_AMD29K__>,<0>)
+ _define__(<_I80386__>,<0>)
+ _define__(<_I960__>,<0>)
+ _define__(<_M680X0__>,<0>)
+ _define__(<_SPARC__>,<0>)
+ _define__(<_VAX__>,<0>)
+
+ _divert__<>
+
+ PARTIC.m4: A file that turns on whichever options you actually
+ want the manual configured for, in this particular
+ instance. Its contents are similar to one or more of
+ the lines in "none.m4", but of course the second
+ argument to _define__ is <1> rather than <0>.
+
+ This is also a convenient place to _define__ any macros
+ that you want to expand to different text for
+ different configurations---for example, the name of
+ the program being described.
+
+Naturally, these are just suggested conventions; you could put your macro
+definitions in any files or combinations of files you like.
+
+These macros use the characters < and > as m4 quotes; if you need
+these characters in your text, you will also want to use the macros
+_0__ and _1__ from this package---see the description of "Quote
+Handling" in the "Implementation" section below.
+
+B. WHAT GOES IN THE PRE-TEXINFO SOURCE
+
+For the most part, the text of your book. In addition, you can
+have text that is included only conditionally, using the macros
+_if__ and _fi__ defined below. They BOTH take an argument! This is
+primarily meant for readability (so a human can more easily see what
+conditional end matches what conditional beginning), but the argument
+is actually used in the _fi__ as well as the _if__ implementation.
+You should always give a _fi__ the same argument as its matching
+_if__. Other arguments may appear to work for a while, but are almost
+certain to produce the wrong output for some configurations.
+
+For example, here is an excerpt from the very beginning of the
+documentation for GNU as, to name the info file appropriately for
+different configurations:
+ _if__(_ALL_ARCH__)
+ @setfilename as.info
+ _fi__(_ALL_ARCH__)
+ _if__(_M680X0__ && !_ALL_ARCH__)
+ @setfilename as-m680x0.info
+ _fi__(_M680X0__ && !_ALL_ARCH__)
+ _if__(_AMD29K__ && !_ALL_ARCH__)
+ @setfilename as-29k.info
+ _fi__(_AMD29K__ && !_ALL_ARCH__)
+
+Note that you can use Boolean expressions in the arguments; the
+expression language is that of the built-in m4 macro `eval', described
+in the m4 manual.
+
+IV. IMPLEMENTATION
+
+A.PRIMITIVE RENAMING
+First, we redefine m4's built-ins to avoid conflict with plain text.
+The naming convention used is that our macros all begin with a single
+underbar and end with two underbars. The asymmetry is meant to avoid
+conflict with some other conventions (which we may want to document) that
+are intended to avoid conflict, like ANSI C predefined macros.
+
+define(`_undefine__',defn(`undefine'))
+define(`_define__',defn(`define'))
+define(`_defn__',defn(`defn'))
+define(`_ppf__',`_define__(`_$1__',_defn__(`$1'))_undefine__(`$1')')
+_ppf__(`builtin')
+_ppf__(`changecom')
+_ppf__(`changequote')
+_ppf__(`decr')
+_ppf__(`define')
+_ppf__(`defn')
+_ppf__(`divert')
+_ppf__(`divnum')
+_ppf__(`dnl')
+_ppf__(`dumpdef')
+_ppf__(`errprint')
+_ppf__(`esyscmd')
+_ppf__(`eval')
+_ppf__(`format')
+_ppf__(`ifdef')
+_ppf__(`ifelse')
+_ppf__(`include')
+_ppf__(`incr')
+_ppf__(`index')
+_ppf__(`len')
+_ppf__(`m4exit')
+_ppf__(`m4wrap')
+_ppf__(`maketemp')
+_ppf__(`patsubst')
+_ppf__(`popdef')
+_ppf__(`pushdef')
+_ppf__(`regexp')
+_ppf__(`shift')
+_ppf__(`sinclude')
+_ppf__(`substr')
+_ppf__(`syscmd')
+_ppf__(`sysval')
+_ppf__(`traceoff')
+_ppf__(`traceon')
+_ppf__(`translit')
+_ppf__(`undefine')
+_ppf__(`undivert')
+_ppf__(`unix')
+
+B. QUOTE HANDLING.
+
+The characters used as quotes by M4, by default, are unfortunately
+quite likely to occur in ordinary text. To avoid surprises, we will
+use the characters <> ---which are just as suggestive (more so to
+Francophones, perhaps) but a little less common in text (save for
+those poor Francophones. You win some, you lose some). Still, we
+expect also to have to set < and > occasionally in text; to do that,
+we define a macro to turn off quote handling (_0__) and a macro to
+turn it back on (_1__), according to our convention.
+
+ BEWARE: This seems to make < and > unusable as relational operations
+ in calls to the builtin "eval". So far I've gotten
+ along without; but a better choice may be possible.
+
+Note that we postponed this for a while, for convenience in discussing
+the issue and in the primitive renaming---not to mention in defining
+_0__ and _1__ themselves! However, the quote redefinitions MUST
+precede the _if__ / _fi__ definitions, because M4 will expand the text
+as given---if we use the wrong quotes here, we will get the wrong
+quotes when we use the conditionals.
+
+_define__(_0__,`_changequote__(,)')_define__(_1__,`_changequote__(<,>)')
+_1__
+
+C. CONDITIONALS
+
+We define two macros, _if__ and _fi__. BOTH take arguments! This is
+meant both to help the human reader match up a _fi__ with its
+corresponding _if__ and to aid in the implementation. You may use the
+full expression syntax supported by M4 (see docn of `eval' builtin in
+the m4 manual).
+
+The conditional macros are carefully defined to avoid introducing
+extra whitespace (i.e., blank lines or blank characters). One side
+effect exists---
+
+ BEWARE: text following an `_if__' on the same line is
+ DISCARDED even if the condition is true; text
+ following a `_fi__' on the same line is also
+ always discarded.
+
+The recommended convention is to always place _if__ and _fi__ on a
+line by themselves. This will also aid the human reader. TeX won't
+care about the line breaks; as for info, you may want to insert calls
+to `@refill' at the end of paragraphs containing conditionalized text,
+where you don't want line breaks separating unconditional from
+conditional text. info formatting will then give you nice looking
+paragraphs in the info file.
+
+Nesting: conditionals are designed to nest, in the following way:
+*nothing* is output between an outer pair of false conditionals, even
+if there are true conditionals inside. A false conditional "defeats"
+all conditionals within it. The counter _IF_FS__ is used to
+implement this; kindly avoid redefining it directly.
+
+_define__(<_IF_FS__>,<0>)
+
+NOTE: The definitions for our "pushf" and "popf" macros use eval
+rather than incr and decr, because GNU m4 (0.75) tries to call eval
+for us when we say "incr" or "decr"---but doesn't notice we've changed
+eval's name.
+
+_define__(
+ <_pushf__>,
+ <_define__(<_IF_FS__>,
+ _eval__((_IF_FS__)+1))>)
+_define__(
+ <_popf__>,
+ <_ifelse__(0,_IF_FS__,
+ <<>_dnl__<>>,
+ <_define__(<_IF_FS__>,_eval__((_IF_FS__)-1))>)>)
+
+_define__(
+ <_if__>,
+ <_ifelse__(1,_eval__( ($1) ),
+ <<>_dnl__<>>,
+ <_pushf__<>_divert__(-1)>)>)
+_define__(
+ <_fi__>,
+ <_ifelse__(1,_eval__( ($1) ),
+ <<>_dnl__<>>,
+ <_popf__<>_ifelse__(0,_IF_FS__,
+ <_divert__<>_dnl__<>>,<>)>)>)
+
+D. CHAPTER/SECTION MACRO
+In a parametrized manual, the heading level may need to be calculated;
+for example, a manual that has a chapter on machine dependencies
+should be conditionally structured as follows:
+ - IF the manual is configured for a SINGLE machine type, use
+the chapter heading for that machine type, and run headings down
+from there (top level for a particular machine is chapter, then within
+that we have section, subsection etc);
+ - ELSE, if MANY machine types are described in the chapter,
+use a generic chapter heading such as "@chapter Machine Dependencies",
+use "section" for the top level description of EACH machine, and run
+headings down from there (top level for a particular machine is
+section, then within that we have subsection, subsubsection etc).
+
+The macro <_CHAPSEC__> is for this purpose: its argument is evaluated (so
+you can construct expressions to express choices such as above), then
+expands as follows:
+ 0: @chapter
+ 1: @section
+ 2: @subsection
+ 3: @subsubsection
+ ...and so on.
+
+_define__(<_CHAPSEC__>,<@_cs__(_eval__($1))>)
+_define__(<_cs__>,<_ifelse__(
+ 0, $1, <chapter>,
+ 1, $1, <section>,
+ <sub<>_cs__(_eval__($1 - 1))>)>)
+
+_divert__<>_dnl__<>
diff --git a/gnu/usr.bin/as/doc/sparc.m4 b/gnu/usr.bin/as/doc/sparc.m4
new file mode 100644
index 0000000..121855a
--- /dev/null
+++ b/gnu/usr.bin/as/doc/sparc.m4
@@ -0,0 +1,8 @@
+_divert__(-1)
+_define__(<_SPARC__>,<1>)
+_define__(<_HOST__>,<SPARC>)
+_define__(<_MACH_DEP__>,<Sparc-Dependent>)
+_define__(<_IEEEFLOAT__>,1) IEEE floating point
+_define__(<_W32__>,1) 32-bit words
+_define__(<_W16__>,0)
+_divert__<>
diff --git a/gnu/usr.bin/as/doc/vax.m4 b/gnu/usr.bin/as/doc/vax.m4
new file mode 100644
index 0000000..009e334
--- /dev/null
+++ b/gnu/usr.bin/as/doc/vax.m4
@@ -0,0 +1,7 @@
+_divert__(-1)
+_define__(<_VAX__>,<1>)
+_define__(<_HOST__>,<VAX>)
+_define__(<_MACH_DEP__>,<VAX-Dependent>)
+_define__(<_W32__>,0)
+_define__(<_W16__>,1) 16-bit words
+_divert__<>
diff --git a/gnu/usr.bin/as/doc/vintage.m4 b/gnu/usr.bin/as/doc/vintage.m4
new file mode 100644
index 0000000..d5913be
--- /dev/null
+++ b/gnu/usr.bin/as/doc/vintage.m4
@@ -0,0 +1,11 @@
+_divert__(-1)
+<$Id: vintage.m4,v 1.1 1993/10/02 21:00:29 pk Exp $>
+_define__(<_ALL_ARCH__>,<1>)
+_define__(<_GENERIC__>,<1>) In case none.m4 changes its mind abt default
+
+_define__(<_AOUT__>,<1>)
+
+_define__(<_M680X0__>,<1>)
+_define__(<_SPARC__>,<1>)
+
+_divert__<>
diff --git a/gnu/usr.bin/as/expr.c b/gnu/usr.bin/as/expr.c
new file mode 100644
index 0000000..413917d
--- /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.3 1993/10/02 20:57:26 pk 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..2706d4d
--- /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.3 1993/10/02 20:57:27 pk 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..28d8008
--- /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/10/02 20:57:28 pk 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..8fcdb52
--- /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/10/02 20:57:29 pk 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-const.c b/gnu/usr.bin/as/flonum-const.c
new file mode 100644
index 0000000..617e585
--- /dev/null
+++ b/gnu/usr.bin/as/flonum-const.c
@@ -0,0 +1,157 @@
+/* flonum_const.c - Useful Flonum constants
+ 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. */
+
+#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 VMS
+dummy1()
+{
+}
+#endif
+/* end: flonum_const.c */
diff --git a/gnu/usr.bin/as/flonum-copy.c b/gnu/usr.bin/as/flonum-copy.c
new file mode 100644
index 0000000..3a51f06
--- /dev/null
+++ b/gnu/usr.bin/as/flonum-copy.c
@@ -0,0 +1,76 @@
+/* flonum_copy.c - copy a flonum
+ 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. */
+
+#include "flonum.h"
+#ifdef USG
+#define bzero(s,n) memset(s,0,n)
+#define bcopy(from,to,n) memcpy(to,from,n)
+#endif
+
+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)
+ {
+ bzero ((char *)(out->low + in_length + 1), out_length - in_length);
+ }
+ }
+ bcopy ((char *)(in->low), (char *)(out->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 ! */
+ bcopy ((char *)(in->low + shorten),(char *)( out->low), (int)((out_length + 1) * sizeof(LITTLENUM_TYPE)));
+ out -> leader = out -> high;
+ out -> exponent = in -> exponent + shorten;
+ }
+ } /* if any significant bits */
+}
+
+/* end: 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..41e90bd
--- /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.3 1993/10/02 20:57:30 pk 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..a1a8f08
--- /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.3 1993/10/02 20:57:31 pk 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..208aa7d
--- /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.3 1993/10/02 20:57:31 pk 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..4532dda
--- /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.3 1993/10/02 20:57:32 pk 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..68a5f14
--- /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 1993/10/02 20:57:34 pk 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: ");
+ gets(answer);
+ 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);
+ gets(answer);
+ /* 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);
+ gets(answer);
+ 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..6918561
--- /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.3 1993/10/02 20:57:35 pk 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..d27d4b3
--- /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.3 1993/10/02 20:57:36 pk 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..3b124cc
--- /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.3 1993/10/02 20:57:37 pk 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..5c88c7c
--- /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.3 1993/10/02 20:57:38 pk 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..73df1a2
--- /dev/null
+++ b/gnu/usr.bin/as/input-scrub.c
@@ -0,0 +1,436 @@
+/* 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 1993/10/02 20:57:39 pk 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 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. */
+
+char *physical_input_file;
+char *logical_input_file;
+
+typedef unsigned int line_numberT; /* 1-origin line number in a source file. */
+/* A line ends in '\n' or eof. */
+
+line_numberT physical_input_line;
+line_numberT 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];
+ int buffer_length;
+ char *physical_input_file;
+ char *logical_input_file;
+ line_numberT physical_input_line;
+ line_numberT 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 */
+};
+
+#if __STDC__ == 1
+static void as_1_char(unsigned int c, FILE *stream);
+#else /* __STDC__ */
+static void as_1_char();
+#endif /* not __STDC__ */
+
+/* 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(). */
+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(save_source, saved->save_source, sizeof(save_source));
+ saved->next_saved_file = next_saved_file;
+ saved->input_file_save = input_file_push();
+
+ input_scrub_begin(); /* Reinitialize! */
+
+ return((char *) saved);
+} /* input_scrub_push() */
+
+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(saved->save_source, 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((long)(BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE));
+ memcpy(buffer_start, BEFORE_STRING, (int) BEFORE_SIZE);
+
+ /* Line number things. */
+ logical_input_line = 0;
+ 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;
+
+#ifdef DONTDEF
+ if (preprocess) {
+ if (save_buffer) {
+ *bufp = save_buffer;
+ save_buffer = 0;
+ }
+ limit = input_file_give_next_buffer(buffer_start+BEFORE_SIZE);
+ if (!limit) {
+ partial_where = 0;
+ if (partial_size)
+ as_warn("Partial line at end of file ignored");
+ return partial_where;
+ }
+
+ if (partial_size)
+ memcpy(partial_where, save_source, (int) AFTER_SIZE);
+ do_scrub(partial_where, partial_size,
+ buffer_start + BEFORE_SIZE,
+ limit - (buffer_start + BEFORE_SIZE),
+ &out_string, &out_length);
+ limit=out_string + out_length;
+ for (p=limit;*--p != '\n';)
+ ;
+ p++;
+ if (p <= buffer_start+BEFORE_SIZE)
+ as_fatal("Source line too long. Please change file '%s' and re-make the 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);
+
+ save_buffer = *bufp;
+ *bufp = out_string;
+
+ return partial_where;
+ }
+
+ /* We're not preprocessing. Do the right thing */
+#endif
+ if (partial_size) {
+ memcpy(buffer_start + BEFORE_SIZE, partial_where, (int) partial_size);
+ memcpy(buffer_start + BEFORE_SIZE, save_source, (int) 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;
+ /* ++ logical_input_line; FIXME-now remove this. */
+}
+
+/*
+ * new_logical_line()
+ *
+ * Tells us what the new logical line number and file are.
+ * If the line_number is <0, we don't change the current logical line number.
+ * 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;
+ } /* if we have a line number */
+} /* new_logical_line() */
+
+/*
+ * a s _ w h e r e ()
+ *
+ * Write a line to stderr locating where we are in reading
+ * input source files.
+ * As a sop to the debugger of AS, pretty-print the offending line.
+ */
+void as_where() {
+ char *p;
+ line_numberT line;
+ extern char *myname;
+
+ if (logical_input_file && (logical_input_line > 0)) {
+ p = logical_input_file;
+ line = logical_input_line;
+ } else {
+ p = physical_input_file;
+ line = physical_input_line;
+ } /* line number should match file name */
+
+ fprintf(stderr, "%s: %s:%u: ", myname, p, line);
+
+ return;
+} /* 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(*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);
+}
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* 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..2f8b1f0
--- /dev/null
+++ b/gnu/usr.bin/as/listing.c
@@ -0,0 +1,849 @@
+/* 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.1 1993/10/02 20:57:40 pk Exp $";
+#endif
+
+#include "as.h"
+
+#ifndef NO_LISTING
+
+#include <obstack.h>
+#include "input-file.h"
+#include "targ-cpu.h"
+
+#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
+
+
+/* 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;
+
+static struct list_info_struct *head;
+struct list_info_struct *listing_tail;
+extern int listing;
+extern unsigned int physical_input_line;
+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;
+
+static void
+ listing_message(name, message)
+char *name;
+char *message;
+{
+ unsigned int l = strlen(name) + strlen(message) + 1;
+ char *n = malloc(l);
+ strcpy(n,name);
+ strcat(n,message);
+ if (listing_tail != (list_info_type *)NULL) {
+ listing_tail->message = n;
+ }
+
+ return;
+} /* lising_message() */
+
+void
+ listing_warning(message)
+char *message;
+{
+ listing_message("Warning:", message);
+}
+
+void
+ listing_error(message)
+char *message;
+{
+ listing_message("Error:", message);
+}
+
+static file_info_type *file_info_head;
+
+static file_info_type *
+ file_info(file_name)
+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(strlen(file_name)+1);
+ strcpy(p->filename, file_name);
+ p->linenum = 0;
+ p->end_pending = 0;
+
+ p->file = fopen(p->filename,"r");
+ return(p);
+} /* file_info() */
+
+
+static void
+ new_frag()
+{
+ frag_wane(frag_now);
+ frag_new(0);
+}
+
+void
+ listing_newline(ps)
+char *ps;
+{
+ char *s = ps;
+ extern char *file_name;
+ static unsigned int last_line = 0xffff ;
+
+
+ list_info_type *new;
+ if (physical_input_line != last_line) {
+ last_line = physical_input_line;
+ new_frag();
+
+ new = (list_info_type *) malloc(sizeof(list_info_type));
+ new->frag = frag_now;
+ new->line = physical_input_line ;
+ new->file = file_info(file_name);
+
+ 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();
+ }
+
+ return;
+} /* listing_newline() */
+
+
+/* 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->end_pending == 10) {
+ *p ++ = '\n';
+ rewind(file->file);
+ 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++ = 'E';
+ *p++ = 'O';
+ *p++ = 'F';
+ }
+
+ file->linenum++;
+ *p++ = 0;
+ return(line);
+} /* buffer_line() */
+
+static 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;
+ }
+
+ return;
+} /* listing_page() */
+
+
+static unsigned int
+ calc_hex(list)
+list_info_type *list;
+{
+ list_info_type *first = list;
+ list_info_type *last = first;
+ unsigned int address = ~0;
+
+ fragS *frag;
+ fragS *frag_ptr;
+
+ unsigned int byte_in_frag = 0;
+
+ int anything = 0;
+
+ /* 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 */
+ 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++;
+ }
+
+ /* 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;
+ }
+ data_buffer[data_buffer_size++] = '*';
+ data_buffer[data_buffer_size++] = '*';
+
+ byte_in_frag++;
+ }
+
+ frag_ptr = frag_ptr->fr_next;
+ }
+
+ data_buffer[data_buffer_size++] = 0;
+ return address;
+} /* calc_hex() */
+
+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);
+ }
+ }
+} /* print_lines() */
+
+
+static void
+ list_symbol_table()
+{
+ extern symbolS *symbol_rootP;
+ symbolS *ptr;
+
+ eject = 1;
+ listing_page(0);
+ printf("DEFINED SYMBOLS\n");
+ on_page++;
+
+ for (ptr = symbol_rootP; ptr != (symbolS*)NULL; ptr = symbol_next(ptr)) {
+ if (ptr->sy_frag->line) {
+ if (strlen(S_GET_NAME(ptr))) {
+ printf("%20s:%-5d %2d:%08x %s \n",
+ ptr->sy_frag->line->file->filename,
+ ptr->sy_frag->line->line,
+ S_GET_SEGMENT(ptr),
+ S_GET_VALUE(ptr),
+ S_GET_NAME(ptr));
+
+ on_page++;
+ listing_page(0);
+ }
+ }
+
+ }
+
+ printf("\n");
+ on_page++;
+ listing_page(0);
+ printf("UNDEFINED SYMBOLS\n");
+ on_page++;
+ listing_page(0);
+
+ for (ptr = symbol_rootP; ptr != (symbolS*)NULL; ptr = symbol_next(ptr)) {
+ if (ptr && strlen(S_GET_NAME(ptr)) != 0) {
+ if (ptr->sy_frag->line == 0) {
+ printf("%s\n", S_GET_NAME(ptr));
+ on_page++;
+ listing_page(0);
+ }
+ }
+ }
+
+ return;
+} /* list_symbol_table() */
+
+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);
+ }
+ }
+
+ return;
+} /* print_source() */
+
+/* Sometimes the user doesn't want to be bothered by the debugging
+ records inserted by the compiler, see if the line is suspicioous */
+
+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;
+
+ return(0);
+} /* debugging_pseudo() */
+
+void
+ listing_listing(name)
+char *name;
+{
+ char *buffer;
+ char *message;
+ char *p;
+ file_info_type *current_hll_file = (file_info_type *) NULL;
+ int on_page = 0;
+ int show_listing = 1;
+ list_info_type *list = head;
+ unsigned int addr = 0;
+ unsigned int page = 1;
+ unsigned int prev = 0;
+ unsigned int width;
+
+ buffer = malloc(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);
+ }
+
+ 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 {
+
+ p = buffer_line(list->file, buffer, width);
+ }
+
+ list = list->next;
+ }
+ free(buffer);
+} /* listing_listing() */
+
+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();
+ }
+} /* listing_print() */
+
+
+void
+ listing_file(name)
+char *name;
+{
+ fn = name;
+}
+
+void
+ listing_eject()
+{
+ listing_tail->edict = EDICT_EJECT;
+ return;
+}
+
+void
+ listing_flags()
+{
+
+}
+
+void
+ listing_list(on)
+unsigned int on;
+{
+ listing_tail->edict = on ? EDICT_LIST : EDICT_NOLIST;
+}
+
+
+void
+ listing_psize()
+{
+ paper_height = get_absolute_expression();
+
+ if (paper_height < 0 || paper_height > 1000) {
+ paper_height = 0;
+ as_warn("strantge paper height, set to no form");
+ }
+
+ if (*input_line_pointer == ',') {
+ input_line_pointer++;
+ paper_width = get_absolute_expression();
+ }
+
+ return;
+} /* listing_psize() */
+
+
+void
+ listing_title(depth)
+unsigned int depth;
+{
+ char *start;
+ char *title;
+ 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;
+ title = malloc(length + 1);
+ memcpy(title, start, length);
+ title[length] = 0;
+ listing_tail->edict = depth ? EDICT_SBTTL : EDICT_TITLE;
+ listing_tail->edict_arg = title;
+ 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");
+ }
+
+ return;
+} /* listing_title() */
+
+
+
+void
+ listing_source_line(line)
+unsigned int line;
+{
+ new_frag();
+ listing_tail->hll_line = line;
+ new_frag();
+ return;
+} /* lising_source_line() */
+
+void
+ listing_source_file(file)
+char *file;
+{
+ listing_tail->hll_file = file_info(file);
+}
+
+#endif /* not NO_LISTING */
+
+/* end of listing.c */
diff --git a/gnu/usr.bin/as/listing.h b/gnu/usr.bin/as/listing.h
new file mode 100644
index 0000000..37a8e87
--- /dev/null
+++ b/gnu/usr.bin/as/listing.h
@@ -0,0 +1,95 @@
+/* This file is listing.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: listing.h,v 1.1 1993/10/02 20:57:41 pk 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); }
+
+
+#if __STDC__ == 1
+
+void listing_eject(void);
+void listing_error(char *message);
+void listing_file(char *name);
+void listing_flags(void);
+void listing_list(unsigned int on);
+void listing_newline(char *ps);
+void listing_print(char *name);
+void listing_psize(void);
+void listing_source_file(char *);
+void listing_source_line(unsigned int);
+void listing_title(unsigned int depth);
+void listing_warning(char *message);
+void listing_width(unsigned int x);
+
+#else /* not __STDC__ */
+
+void listing_eject();
+void listing_error();
+void listing_file();
+void listing_flags();
+void listing_list();
+void listing_newline();
+void listing_print();
+void listing_psize();
+void listing_source_file();
+void listing_source_line();
+void listing_title();
+void listing_warning();
+void listing_width();
+
+#endif /* not __STDC__ */
+
+#else /* NO_LISTING */
+
+#define LISTING_NEWLINE() {;}
+
+/* Dummy functions for when compiled without listing enabled */
+
+#define listing_flags() {;}
+#define listing_list() {;}
+#define listing_eject() {;}
+#define listing_psize() {;}
+#define listing_title(depth) {;}
+#define listing_file(name) {;}
+#define listing_newline(name) {;}
+#define listing_source_line(n) {;}
+#define listing_source_file(n) {;}
+
+#endif /* NO_LISTING */
+
+#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/md.h b/gnu/usr.bin/as/md.h
new file mode 100644
index 0000000..681d027
--- /dev/null
+++ b/gnu/usr.bin/as/md.h
@@ -0,0 +1,57 @@
+/* md.h -machine dependent- */
+
+/* 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. */
+
+/* In theory (mine, at least!) the machine dependent part of the assembler
+ should only have to include one file. This one. -- JF */
+
+/* JF added this here */
+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;
+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 */
+
+char * md_atof();
+void md_assemble();
+void md_begin();
+void md_convert_frag();
+void md_end();
+int md_estimate_size_before_relax();
+void md_number_to_chars();
+
+/* end: md.h */
diff --git a/gnu/usr.bin/as/messages.c b/gnu/usr.bin/as/messages.c
new file mode 100644
index 0000000..b1ba3f7
--- /dev/null
+++ b/gnu/usr.bin/as/messages.c
@@ -0,0 +1,417 @@
+/* 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 1993/10/02 20:57:45 pk Exp $";
+#endif
+
+#include <stdio.h> /* define stderr */
+#include <errno.h>
+
+#include "as.h"
+
+#ifndef NO_STDARG
+#include <stdarg.h>
+#else
+#ifndef NO_VARARGS
+#include <varargs.h>
+#endif /* NO_VARARGS */
+#endif /* NO_STDARG */
+
+/*
+ * 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.
+ */
+
+/*
+ ERRORS
+
+ JF: this is now bogus. We now print more standard error messages
+ that try to look like everyone else's.
+
+ We print the error message 1st, beginning in column 1.
+ All ancillary info starts in column 2 on lines after the
+ key error text.
+ We try to print a location in logical and physical file
+ just after the main error text.
+ Caller then prints any appendices after that, begining all
+ lines with at least 1 space.
+
+ Optionally, we may die.
+ There is no need for a trailing '\n' in your error text format
+ because we supply one.
+
+ as_warn(fmt,args) Like fprintf(stderr,fmt,args) but also call errwhere().
+
+ as_fatal(fmt,args) Like as_warn() but exit with a fatal status.
+
+ */
+
+static int warning_count = 0; /* 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 = 0;
+
+int had_errors() {
+ return(error_count);
+} /* had_errors() */
+
+
+/*
+ * a s _ p e r r o r
+ *
+ * Like perror(3), but with more info.
+ */
+void as_perror(gripe, filename)
+char *gripe; /* Unpunctuated error theme. */
+char *filename;
+{
+#ifndef HAVE_STRERROR
+ extern char *strerror();
+#endif /* HAVE_STRERROR */
+
+ as_where();
+ fprintf(stderr, gripe, filename);
+ fprintf(stderr, "%s.\n", strerror(errno));
+ errno = 0; /* After reporting, clear it. */
+} /* as_perror() */
+
+/*
+ * a s _ t s k t s k ()
+ *
+ * Send to stderr a string (with bell) (JF: Bell is obnoxious!) 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(Format)
+const char *Format;
+{
+ va_list args;
+
+ as_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_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_where();
+ _doprnt (Format, &args, stderr);
+ (void)putc ('\n', stderr);
+ /* as_where(); */
+} /* as_tsktsk */
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+#ifdef DONTDEF
+void as_tsktsk(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an)
+char *format;
+{
+ as_where();
+ fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
+ (void)putc('\n',stderr);
+} /* as_tsktsk() */
+#endif
+/*
+ * a s _ w a r n ()
+ *
+ * Send to stderr a string (with bell) (JF: Bell is obnoxious!) 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_warn(Format)
+const char *Format;
+{
+ va_list args;
+ char buffer[200];
+
+ if (!flagseen['W']) {
+ ++warning_count;
+ as_where();
+ va_start(args, Format);
+ fprintf(stderr,"Warning: ");
+ vsprintf(buffer, Format, args);
+ fprintf(stderr, buffer);
+#ifndef NO_LISTING
+ listing_warning(buffer);
+#endif
+ va_end(args);
+ (void) putc('\n', stderr);
+ }
+} /* as_warn() */
+#else
+#ifndef NO_VARARGS
+void as_warn(Format,va_alist)
+char *Format;
+va_dcl
+{
+ va_list args;
+ char buffer[200];
+
+ if (!flagseen['W']) {
+ ++warning_count;
+ as_where();
+ va_start(args);
+ fprintf(stderr,"Warning: ");
+ vsprintf(buffer, Format, args);
+ fprintf(stderr,buffer);
+#ifndef NO_LISTING
+ listing_warning(buffer);
+#endif
+ va_end(args);
+ (void) putc('\n', stderr);
+ }
+} /* as_warn() */
+#else
+/*VARARGS1 */
+as_warn(Format,args)
+char *Format;
+{
+ /* -W supresses warning messages. */
+ if (! flagseen['W']) {
+ ++warning_count;
+ as_where();
+ _doprnt (Format, &args, stderr);
+ (void)putc ('\n', stderr);
+ /* as_where(); */
+ }
+} /* as_warn() */
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+#ifdef DONTDEF
+void as_warn(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an)
+char *format;
+{
+ if (!flagseen['W']) {
+ ++warning_count;
+ as_where();
+ fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
+ (void)putc('\n',stderr);
+ }
+} /* as_warn() */
+#endif
+/*
+ * a s _ b a d ()
+ *
+ * Send to stderr a string (with bell) (JF: Bell is obnoxious!) 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(Format)
+const char *Format;
+{
+ va_list args;
+ char buffer[200];
+
+ ++error_count;
+ as_where();
+ va_start(args, Format);
+ fprintf(stderr,"Error: ");
+
+ vsprintf(buffer, Format, args);
+ fprintf(stderr,buffer);
+#ifndef NO_LISTING
+ listing_error(buffer);
+#endif
+ va_end(args);
+ (void) putc('\n', stderr);
+} /* as_bad() */
+#else
+#ifndef NO_VARARGS
+void as_bad(Format,va_alist)
+char *Format;
+va_dcl
+{
+ va_list args;
+ char buffer[200];
+
+ ++error_count;
+ as_where();
+ va_start(args);
+ vsprintf(buffer, Format, args);
+ fprintf(stderr,buffer);
+#ifndef NO_LISTING
+ listing_error(buffer);
+#endif
+
+ va_end(args);
+ (void) putc('\n', stderr);
+} /* as_bad() */
+#else
+/*VARARGS1 */
+as_bad(Format,args)
+char *Format;
+{
+ ++error_count;
+
+ as_where();
+ fprintf(stderr,"Error: ");
+ _doprnt (Format, &args, stderr);
+ (void)putc ('\n', stderr);
+ /* as_where(); */
+} /* as_bad() */
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+#ifdef DONTDEF
+void as_bad(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an)
+char *format;
+{
+ ++error_count;
+ as_where();
+ fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
+ (void)putc('\n',stderr);
+} /* as_bad() */
+#endif
+
+/*
+ * a s _ f a t a l ()
+ *
+ * Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a fatal
+ * message, and locate stdsource 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(Format)
+const char *Format;
+{
+ va_list args;
+
+ as_where();
+ va_start(args, Format);
+ fprintf (stderr, "FATAL:");
+ 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_where();
+ va_start(args);
+ fprintf (stderr, "FATAL:");
+ vfprintf(stderr, Format, args);
+ (void) putc('\n', stderr);
+ va_end(args);
+ exit(33);
+} /* as_fatal() */
+#else
+/*VARARGS1 */
+as_fatal(Format, args)
+char *Format;
+{
+ as_where();
+ fprintf(stderr,"FATAL:");
+ _doprnt (Format, &args, stderr);
+ (void)putc ('\n', stderr);
+ /* as_where(); */
+ exit(33); /* What is a good exit status? */
+} /* as_fatal() */
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+#ifdef DONTDEF
+void as_fatal(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an)
+char *Format;
+{
+ as_where();
+ fprintf (stderr, "FATAL:");
+ fprintf(stderr, Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
+ (void) putc('\n', stderr);
+ exit(33);
+} /* as_fatal() */
+#endif
+
+/* 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..ac5b158
--- /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/10/02 20:57:45 pk 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/objrecdef.h b/gnu/usr.bin/as/objrecdef.h
new file mode 100644
index 0000000..fca8af4
--- /dev/null
+++ b/gnu/usr.bin/as/objrecdef.h
@@ -0,0 +1,255 @@
+/*
+ *
+ * $OBJRECDEF
+ * Generated automatically by "vms_struct Version 1.00"
+ * Created from VMS definition file "objrecdef.mar"
+ * Mon Oct 14 14:01:29 1985
+ *
+ */
+struct OBJREC {
+ unsigned char obj$b_rectyp;
+ unsigned char obj$b_subtyp;
+ unsigned char obj$b_mhd_strlv;
+ unsigned char obj$b_mhd_recsz[2];
+ unsigned char obj$t_mhd_name[1];
+ };
+
+#define OBJ$C_HDR 0
+#define OBJ$C_HDR_MHD 0
+#define OBJ$C_HDR_LNM 1
+#define OBJ$C_HDR_SRC 2
+#define OBJ$C_HDR_TTL 3
+#define OBJ$C_HDR_CPR 4
+#define OBJ$C_HDR_MTC 5
+#define OBJ$C_HDR_GTX 6
+#define OBJ$C_GSD 1
+#define OBJ$C_GSD_PSC 0
+#define OBJ$C_GSD_SYM 1
+#define OBJ$C_GSD_EPM 2
+#define OBJ$C_GSD_PRO 3
+#define OBJ$C_GSD_SYMW 4
+#define OBJ$C_GSD_EPMW 5
+#define OBJ$C_GSD_PROW 6
+#define OBJ$C_GSD_IDC 7
+#define OBJ$C_GSD_ENV 8
+#define OBJ$C_GSD_LSY 9
+#define OBJ$C_GSD_LEPM 10
+#define OBJ$C_GSD_LPRO 11
+#define OBJ$C_GSD_SPSC 12
+#define OBJ$C_TIR 2
+#define OBJ$C_EOM 3
+#define OBJ$C_DBG 4
+#define OBJ$C_TBT 5
+#define OBJ$C_LNK 6
+#define OBJ$C_EOMW 7
+#define OBJ$C_MAXRECTYP 7
+#define OBJ$K_SUBTYP 1
+#define OBJ$C_SUBTYP 1
+#define OBJ$C_MAXRECSIZ 2048
+#define OBJ$C_STRLVL 0
+#define OBJ$C_SYMSIZ 31
+#define OBJ$C_STOREPLIM -1
+#define OBJ$C_PSCALILIM 9
+
+#define MHD$C_MHD 0
+#define MHD$C_LNM 1
+#define MHD$C_SRC 2
+#define MHD$C_TTL 3
+#define MHD$C_CPR 4
+#define MHD$C_MTC 5
+#define MHD$C_GTX 6
+#define MHD$C_MAXHDRTYP 6
+
+#define GSD$K_ENTRIES 1
+#define GSD$C_ENTRIES 1
+#define GSD$C_PSC 0
+#define GSD$C_SYM 1
+#define GSD$C_EPM 2
+#define GSD$C_PRO 3
+#define GSD$C_SYMW 4
+#define GSD$C_EPMW 5
+#define GSD$C_PROW 6
+#define GSD$C_IDC 7
+#define GSD$C_ENV 8
+#define GSD$C_LSY 9
+#define GSD$C_LEPM 10
+#define GSD$C_LPRO 11
+#define GSD$C_SPSC 12
+#define GSD$C_SYMV 13
+#define GSD$C_EPMV 14
+#define GSD$C_PROV 15
+#define GSD$C_MAXRECTYP 15
+
+#define GSY$M_WEAK 1
+#define GSY$M_DEF 2
+#define GSY$M_UNI 4
+#define GSY$M_REL 8
+
+#define GPS$M_PIC 1
+#define GPS$M_LIB 2
+#define GPS$M_OVR 4
+#define GPS$M_REL 8
+#define GPS$M_GBL 16
+#define GPS$M_SHR 32
+#define GPS$M_EXE 64
+#define GPS$M_RD 128
+#define GPS$M_WRT 256
+#define GPS$M_VEC 512
+#define GPS$K_NAME 9
+#define GPS$C_NAME 9
+
+#define TIR$C_STA_GBL 0
+#define TIR$C_STA_SB 1
+#define TIR$C_STA_SW 2
+#define TIR$C_STA_LW 3
+#define TIR$C_STA_PB 4
+#define TIR$C_STA_PW 5
+#define TIR$C_STA_PL 6
+#define TIR$C_STA_UB 7
+#define TIR$C_STA_UW 8
+#define TIR$C_STA_BFI 9
+#define TIR$C_STA_WFI 10
+#define TIR$C_STA_LFI 11
+#define TIR$C_STA_EPM 12
+#define TIR$C_STA_CKARG 13
+#define TIR$C_STA_WPB 14
+#define TIR$C_STA_WPW 15
+#define TIR$C_STA_WPL 16
+#define TIR$C_STA_LSY 17
+#define TIR$C_STA_LIT 18
+#define TIR$C_STA_LEPM 19
+#define TIR$C_MAXSTACOD 19
+#define TIR$C_MINSTOCOD 20
+#define TIR$C_STO_SB 20
+#define TIR$C_STO_SW 21
+#define TIR$C_STO_L 22
+#define TIR$C_STO_BD 23
+#define TIR$C_STO_WD 24
+#define TIR$C_STO_LD 25
+#define TIR$C_STO_LI 26
+#define TIR$C_STO_PIDR 27
+#define TIR$C_STO_PICR 28
+#define TIR$C_STO_RSB 29
+#define TIR$C_STO_RSW 30
+#define TIR$C_STO_RL 31
+#define TIR$C_STO_VPS 32
+#define TIR$C_STO_USB 33
+#define TIR$C_STO_USW 34
+#define TIR$C_STO_RUB 35
+#define TIR$C_STO_RUW 36
+#define TIR$C_STO_B 37
+#define TIR$C_STO_W 38
+#define TIR$C_STO_RB 39
+#define TIR$C_STO_RW 40
+#define TIR$C_STO_RIVB 41
+#define TIR$C_STO_PIRR 42
+#define TIR$C_MAXSTOCOD 42
+#define TIR$C_MINOPRCOD 50
+#define TIR$C_OPR_NOP 50
+#define TIR$C_OPR_ADD 51
+#define TIR$C_OPR_SUB 52
+#define TIR$C_OPR_MUL 53
+#define TIR$C_OPR_DIV 54
+#define TIR$C_OPR_AND 55
+#define TIR$C_OPR_IOR 56
+#define TIR$C_OPR_EOR 57
+#define TIR$C_OPR_NEG 58
+#define TIR$C_OPR_COM 59
+#define TIR$C_OPR_INSV 60
+#define TIR$C_OPR_ASH 61
+#define TIR$C_OPR_USH 62
+#define TIR$C_OPR_ROT 63
+#define TIR$C_OPR_SEL 64
+#define TIR$C_OPR_REDEF 65
+#define TIR$C_OPR_DFLIT 66
+#define TIR$C_MAXOPRCOD 66
+#define TIR$C_MINCTLCOD 80
+#define TIR$C_CTL_SETRB 80
+#define TIR$C_CTL_AUGRB 81
+#define TIR$C_CTL_DFLOC 82
+#define TIR$C_CTL_STLOC 83
+#define TIR$C_CTL_STKDL 84
+#define TIR$C_MAXCTLCOD 84
+
+/*
+ * Debugger symbol definitions: These are done by hand, as no
+ * machine-readable version seems
+ * to be available.
+ */
+#define DST$C_C 7 /* Language == "C" */
+#define DST$C_VERSION 153
+#define DST$C_SOURCE 155 /* Source file */
+#define DST$C_PROLOG 162
+#define DST$C_BLKBEG 176 /* Beginning of block */
+#define DST$C_BLKEND 177 /* End of block */
+#define DST$C_ENTRY 181
+#define DST$C_PSECT 184
+#define DST$C_LINE_NUM 185 /* Line Number */
+#define DST$C_LBLORLIT 186
+#define DST$C_LABEL 187
+#define DST$C_MODBEG 188 /* Beginning of module */
+#define DST$C_MODEND 189 /* End of module */
+#define DST$C_RTNBEG 190 /* Beginning of routine */
+#define DST$C_RTNEND 191 /* End of routine */
+#define DST$C_DELTA_PC_W 1 /* Incr PC */
+#define DST$C_INCR_LINUM 2 /* Incr Line # */
+#define DST$C_INCR_LINUM_W 3 /* Incr Line # */
+#define DST$C_SET_LINUM_INCR 4
+#define DST$C_SET_LINUM_INCR_W 5
+#define DST$C_RESET_LINUM_INCR 6
+#define DST$C_BEG_STMT_MODE 7
+#define DST$C_END_STMT_MODE 8
+#define DST$C_SET_LINE_NUM 9 /* Set Line # */
+#define DST$C_SET_PC 10
+#define DST$C_SET_PC_W 11
+#define DST$C_SET_PC_L 12
+#define DST$C_SET_STMTNUM 13
+#define DST$C_TERM 14 /* End of lines */
+#define DST$C_TERM_W 15 /* End of lines */
+#define DST$C_SET_ABS_PC 16 /* Set PC */
+#define DST$C_DELTA_PC_L 17 /* Incr PC */
+#define DST$C_INCR_LINUM_L 18 /* Incr Line # */
+#define DST$C_SET_LINUM_B 19 /* Set Line # */
+#define DST$C_SET_LINUM_L 20 /* Set Line # */
+#define DST$C_TERM_L 21 /* End of lines */
+/* these are used with DST$C_SOURCE */
+#define DST$C_SRC_FORMFEED 16 /* ^L counts */
+#define DST$C_SRC_DECLFILE 1 /* Declare file */
+#define DST$C_SRC_SETFILE 2 /* Set file */
+#define DST$C_SRC_SETREC_L 3 /* Set record */
+#define DST$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$C_UCHAR 0x02
+#define DBG$C_USINT 0x03
+#define DBG$C_ULINT 0x04
+#define DBG$C_SCHAR 0x06
+#define DBG$C_SSINT 0x07
+#define DBG$C_SLINT 0x08
+#define DBG$C_REAL4 0x0a
+#define DBG$C_REAL8 0x0b
+#define DBG$C_FUNCTION_ADDR 0x17
+#define DBG$C_ADVANCED_TYPE 0xa3
+/* These are the codes that are used to generate the definitions of struct
+ * union and enum records
+ */
+#define DBG$C_ENUM_ITEM 0xa4
+#define DBG$C_ENUM_START 0xa5
+#define DBG$C_ENUM_END 0xa6
+#define DBG$C_STRUCT_START 0xab
+#define DBG$C_STRUCT_ITEM 0xff
+#define DBG$C_STRUCT_END 0xac
+/* These are the codes that are used in the suffix records to determine the
+ * actual data type
+ */
+#define DBG$C_BASIC 0x01
+#define DBG$C_BASIC_ARRAY 0x02
+#define DBG$C_STRUCT 0x03
+#define DBG$C_POINTER 0x04
+#define DBG$C_VOID 0x05
+#define DBG$C_COMPLEX_ARRAY 0x07
+/* These codes are used in the generation of the symbol definition records
+ */
+#define DBG$C_FUNCTION_PARAMETER 0xc9
+#define DBG$C_LOCAL_SYM 0xd9
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..880015f
--- /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.3 1993/10/02 20:57:48 pk 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..f4702a8
--- /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..cc8fe1c
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/i386.h
@@ -0,0 +1,830 @@
+/* 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 1993/10/04 22:53:32 pk 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},
+
+{"", 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..0842786
--- /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..e9c8cb4
--- /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/10/02 21:00:44 pk 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..dda8337
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/m68k.h
@@ -0,0 +1,1996 @@
+/* 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 },
+{"jra", one(0060000), one(0177400), "Bg", m68000up },
+{"jra", one(0047300), one(0177700), "!s", m68000up },
+
+{"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..a65678a
--- /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..2a7621a
--- /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..06632b8
--- /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..3c52464
--- /dev/null
+++ b/gnu/usr.bin/as/opcode/sparc.h
@@ -0,0 +1,871 @@
+
+/* 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.1 1993/10/02 21:00:55 pk 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 },
+
+/* 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 ("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..27099a4
--- /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..7439e86
--- /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.3 1993/10/02 20:57:49 pk 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..e7d7b97
--- /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/10/02 20:57:49 pk 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..cf3c416
--- /dev/null
+++ b/gnu/usr.bin/as/read.c
@@ -0,0 +1,2347 @@
+/* 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.3 1993/11/30 20:55:43 jkh 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 */
+ { "app-file", s_app_file, 0 },
+ { "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();
+}
+
+void s_app_file() {
+ register char *s;
+ int length;
+
+ /* Some assemblers tolerate immediately following '"' */
+ if ((s = demand_copy_string(&length)) != 0) {
+ new_logical_line(s, -1);
+ demand_empty_rest_of_line();
+ }
+#ifdef OBJ_COFF
+ c_dot_file_symbol(s);
+#endif /* OBJ_COFF */
+} /* s_app_file() */
+
+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);
+#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..b03fbab
--- /dev/null
+++ b/gnu/usr.bin/as/read.h
@@ -0,0 +1,149 @@
+/* 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.2 1993/11/03 00:52:16 paul 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[];
+
+#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(void);
+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_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..e0030cd
--- /dev/null
+++ b/gnu/usr.bin/as/struc-symbol.h
@@ -0,0 +1,132 @@
+/* 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.2 1993/11/03 00:52:18 paul 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 */
+
+#define N_REGISTER 30 /* Fake N_TYPE value for SEG_REGISTER */
+
+#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..af2d4e7
--- /dev/null
+++ b/gnu/usr.bin/as/subsegs.c
@@ -0,0 +1,308 @@
+/* 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 1993/10/02 20:57:54 pk 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 {
+ 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);
+#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..4b8e3ce
--- /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.3 1993/10/02 20:57:55 pk 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..066f54e
--- /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.3 1993/10/02 20:57:56 pk 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..535933f
--- /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.3 1993/10/02 20:57:57 pk 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..f36629c
--- /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/10/02 20:57:58 pk 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..b3711c4
--- /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.2 1993/11/03 00:52:27 paul Exp $";
+#endif
+
+char version_string[] = "GNU assembler version 1.92.3, FreeBSD $Revision: 1.2 $\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..dd139f7
--- /dev/null
+++ b/gnu/usr.bin/as/write.c
@@ -0,0 +1,1213 @@
+/* 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.4 1993/12/12 17:01:24 jkh 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);
+#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 */
+ 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'] ||
+ (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..01e7272
--- /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..6962484
--- /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.3 1993/10/02 20:58:02 pk 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..1b26f43
--- /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.3 1993/10/02 20:58:03 pk 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..dad9f57 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 regex.c dfa.c
+DPADD= ${LIBM}
+LDADD= -lm
+CFLAGS+=-I${.CURDIR} -DGAWK
+CLEANFILES+=awk.c y.tab.h
-MAN1= awk.0
+MAN1= awk.1
.include <bsd.prog.mk>
-.include "../../usr.bin/Makefile.inc"
+#.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..d42f9a6 100644
--- a/gnu/usr.bin/awk/array.c
+++ b/gnu/usr.bin/awk/array.c
@@ -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.
@@ -23,9 +23,24 @@
* 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 */
@@ -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;
@@ -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..a98c99d 100644
--- a/gnu/usr.bin/awk/awk.1
+++ b/gnu/usr.bin/awk/awk.1
@@ -1,7 +1,7 @@
.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 GAWK 1 "Apr 18 1994" "Free Software Foundation" "Utility Commands"
.SH NAME
gawk \- pattern scanning and processing language
.SH SYNOPSIS
@@ -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 gawk ,
+since
+.I gawk
+has no pre-defined limits.
.TP \w'\fB\-\^\-copyright\fR'u+1n
.PD 0
.B "\-W compat"
@@ -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"
@@ -248,6 +275,8 @@ This is useful mainly for knowing if the current copy of
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,11 +337,13 @@ option contains a ``/'' character, no path search is performed.
.I Gawk
executes AWK programs in the following order.
First,
+all variable assignments specified via the
+.B \-v
+option are performed.
+Next,
.I gawk
compiles the program into an internal form.
-Next, all variable assignments specified via the
-.B \-v
-option are performed. Then,
+Then,
.I gawk
executes the code in the
.B BEGIN
@@ -359,8 +396,8 @@ 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
@@ -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:
@@ -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
@@ -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.
@@ -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:
@@ -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
@@ -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
@@ -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,
@@ -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
@@ -1610,7 +1681,11 @@ option for implementation specific features is from the \*(PX standard.
When processing arguments,
.I gawk
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() .
@@ -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
@@ -1733,7 +1813,7 @@ 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
@@ -1785,7 +1865,7 @@ a = length($0)
This feature is marked as ``deprecated'' in the \*(PX standard, and
.I gawk
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 gawk
+behaves exactly as if
+.B \-\-posix
+had been specified on the command line.
+If
+.B \-\-lint
+has been specified,
+.I gawk
+will issue a warning message to this effect.
.SH BUGS
The
.B \-F
@@ -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..066bf44 100644
--- a/gnu/usr.bin/awk/awk.h
+++ b/gnu/usr.bin/awk/awk.h
@@ -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.
@@ -24,14 +24,18 @@
*/
/* ------------------------------ 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,14 +168,9 @@ 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"
@@ -173,7 +178,7 @@ extern int pclose P((FILE *));
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
@@ -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
+#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..96411de 100644
--- a/gnu/usr.bin/awk/builtin.c
+++ b/gnu/usr.bin/awk/builtin.c
@@ -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.
@@ -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,27 +239,54 @@ 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;\
}
@@ -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,44 +384,65 @@ 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) {
@@ -372,240 +454,189 @@ retry:
#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);
- ofre -= len;
- olen += 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);
+ len = strlen(obufout);
ofre -= len;
- olen += len;
+ obufout += 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,18 +756,43 @@ 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);
}
+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++;
}
@@ -1026,7 +1095,7 @@ int global;
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..0b3cca1 100644
--- a/gnu/usr.bin/awk/config.h
+++ b/gnu/usr.bin/awk/config.h
@@ -5,7 +5,7 @@
*/
/*
- * 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.
@@ -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..47ad35e 100644
--- a/gnu/usr.bin/awk/dfa.c
+++ b/gnu/usr.bin/awk/dfa.c
@@ -1,182 +1,146 @@
-/* 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
+#ifdef isascii
+#define ISALPHA(C) (isascii(C) && isalpha(C))
+#define ISUPPER(C) (isascii(C) && isupper(C))
+#define ISLOWER(C) (isascii(C) && islower(C))
+#define ISDIGIT(C) (isascii(C) && isdigit(C))
+#define ISXDIGIT(C) (isascii(C) && isxdigit(C))
+#define ISSPACE(C) (isascii(C) && isspace(C))
+#define ISPUNCT(C) (isascii(C) && ispunct(C))
+#define ISALNUM(C) (isascii(C) && isalnum(C))
+#define ISPRINT(C) (isascii(C) && isprint(C))
+#define ISGRAPH(C) (isascii(C) && isgraph(C))
+#define ISCNTRL(C) (isascii(C) && iscntrl(C))
+#else
+#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)
+#endif
+
+#include "regex.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 +151,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 +164,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 +181,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 +234,7 @@ tstbit(b, c)
static void
setbit(b, c)
int b;
- _charset c;
+ charclass c;
{
c[b / INTBITS] |= 1 << b % INTBITS;
}
@@ -240,84 +242,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 +327,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 +466,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 +782,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();
+ regexp(1);
- if (tok == _ALLENDLINE)
- {
- addtok(_ENDLINE);
- addtok(_CAT);
- tok = lex();
- }
+ if (tok != END)
+ dfaerror("Unbalanced )");
- if (tok != _END)
- reg_error("Unbalanced )");
+ addtok(END - d->nregexps);
+ addtok(CAT);
- addtok(_END - r->nregexps);
- addtok(_CAT);
+ if (d->nregexps)
+ addtok(ORTOP);
- if (r->nregexps)
- addtok(_OR);
-
- ++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 +977,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 +1004,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 +1030,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 +1042,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 +1062,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 +1146,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 +1180,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 +1223,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 +1234,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;
- r->searchflag = searchflag;
+#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
- MALLOC(nullable, int, r->depth);
+ d->searchflag = searchflag;
+
+ 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 +1296,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 +1305,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 +1325,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 +1339,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 +1353,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 +1368,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 +1379,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 +1443,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 +1465,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 +1497,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 +1528,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 +1536,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 +1578,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 +1606,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 +1627,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 +1680,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 +1727,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 +1737,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 +1757,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 +1851,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 +1861,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 +1871,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 +1927,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;
+
+ d->talloc = 1;
+ MALLOC(d->tokens, token, d->talloc);
+ d->tindex = d->depth = d->nleaves = d->nregexps = 0;
- r->talloc = 1;
- MALLOC(r->tokens, _token, r->talloc);
- r->tindex = r->depth = r->nleaves = r->nregexps = 0;
+ d->searchflag = 0;
+ d->tralloc = 0;
- r->searchflag = 0;
- r->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");
+ lcopy = malloc(len);
+ if (!lcopy)
+ dfaerror("out of memory");
- /* This is a complete kludge and could potentially break
- \<letter> escapes . . . */
+ /* 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.
-
-Type left right is in
----- ---- ----- -- --
-char c # c # c # c # c
-
-SET 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
+ 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
-)
+ 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/eval.c b/gnu/usr.bin/awk/eval.c
index f640f37..18f67fd 100644
--- a/gnu/usr.bin/awk/eval.c
+++ b/gnu/usr.bin/awk/eval.c
@@ -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.
@@ -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:
@@ -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);
@@ -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);
}
@@ -985,7 +1020,7 @@ NODE *arg_list; /* Node_expression_list of calling args. */
*/
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..17dce9b 100644
--- a/gnu/usr.bin/awk/field.c
+++ b/gnu/usr.bin/awk/field.c
@@ -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.
@@ -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;
@@ -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)
@@ -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..7fe21ec 100644
--- a/gnu/usr.bin/awk/io.c
+++ b/gnu/usr.bin/awk/io.c
@@ -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.
@@ -23,6 +23,9 @@
* 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;
}
/*
@@ -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 {
/*
@@ -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,10 @@ char *mode;
int
devopen(name, mode)
-char *name, *mode;
+const char *name, *mode;
{
int openfd = INVALID_HANDLE;
- char *cp, *ptr;
+ const char *cp, *ptr;
int flag = 0;
struct stat buf;
extern double strtod();
@@ -618,7 +663,7 @@ 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)
@@ -647,7 +692,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 +719,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 +739,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 +798,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__)
+ gid_t groupset[NGROUPS_MAX];
+#else
int groupset[NGROUPS_MAX];
+#endif
int ngroups;
#endif
@@ -755,7 +824,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 +842,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 +872,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);
@@ -939,8 +1006,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 +1026,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 +1034,7 @@ struct redirect *rp;
aval = pclose(kludge);
return (rval < 0 ? rval : aval);
}
-#else /* VMS */
+#else /* VMS || OS2 || MSDOS */
static
struct {
@@ -1016,7 +1084,7 @@ struct redirect *rp;
free(pipes[cur].command);
return rval;
}
-#endif /* VMS */
+#endif /* VMS || OS2 || MSDOS */
#endif /* PIPES_SIMULATED */
@@ -1041,7 +1109,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 +1124,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 +1170,7 @@ NODE *tree;
int
pathopen (file)
-char *file;
+const char *file;
{
int fd = do_pathopen(file);
@@ -1134,12 +1202,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 +1228,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 +1237,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 +1254,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 +1278,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..897daef 100644
--- a/gnu/usr.bin/awk/iop.c
+++ b/gnu/usr.bin/awk/iop.c
@@ -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.
@@ -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..a14efff 100644
--- a/gnu/usr.bin/awk/main.c
+++ b/gnu/usr.bin/awk/main.c
@@ -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.
@@ -55,9 +55,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;
@@ -134,10 +134,19 @@ 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 __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,7 +174,6 @@ 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
@@ -179,11 +187,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 +228,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 +259,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 +273,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 +288,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 +319,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 +338,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 +354,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 +382,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 +439,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 +450,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 +468,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 +500,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 +514,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 +533,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,7 +546,7 @@ 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;
@@ -510,7 +579,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 +589,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 +740,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 +772,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..4bd9f90 100644
--- a/gnu/usr.bin/awk/msg.c
+++ b/gnu/usr.bin/awk/msg.c
@@ -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.
@@ -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..dca4ad1 100644
--- a/gnu/usr.bin/awk/node.c
+++ b/gnu/usr.bin/awk/node.c
@@ -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.
@@ -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');
@@ -101,7 +102,7 @@ register NODE *n;
* (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;
}
@@ -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;
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..1d4ac99 100644
--- a/gnu/usr.bin/awk/protos.h
+++ b/gnu/usr.bin/awk/protos.h
@@ -3,7 +3,7 @@
*/
/*
- * 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.
@@ -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..4ea22c2 100644
--- a/gnu/usr.bin/awk/re.c
+++ b/gnu/usr.bin/awk/re.c
@@ -3,7 +3,7 @@
*/
/*
- * 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.
@@ -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;
@@ -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
index f4dd4c2..6a36f3d 100644
--- a/gnu/usr.bin/awk/regex.c
+++ b/gnu/usr.bin/awk/regex.c
@@ -1,9 +1,13 @@
-/* Extended regular expression matching and search library.
- Copyright (C) 1985, 1989-90 Free Software Foundation, Inc.
+/* Extended regular expression matching and search library,
+ version 0.12.
+ (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 1, or (at your option)
+ 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,
@@ -15,75 +19,63 @@
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
-/* 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. */
+#define _GNU_SOURCE
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
-#ifdef emacs
+#if defined(STDC_HEADERS) && !defined(emacs)
+#include <stddef.h>
+#else
+/* We need this for `regex.h', and perhaps for the Emacs include files. */
+#include <sys/types.h>
+#endif
-/* The `emacs' switch turns on certain special matching commands
- that make sense only in emacs. */
+/* 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"
-/* 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 */
+/* Emacs uses `NULL' as a predicate. */
+#undef NULL
-#include "awk.h"
+#else /* not emacs */
-#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
+/* 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
-#endif /* atarist */
#else
-#if defined(sparc) && !defined(__GNUC__)
-#include <alloca.h>
+#include <strings.h>
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
#else
-char *alloca ();
+char *malloc ();
+char *realloc ();
#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. */
+
+
+/* Define the syntax stuff for \<, \>, etc. */
/* This must be nonzero for the wordchar and notwordchar pattern
commands in re_match_2. */
@@ -91,18 +83,16 @@ long re_set_syntax P((long));
#define Sword 1
#endif
-#define SYNTAX(c) re_syntax_table[c]
-
-
#ifdef SYNTAX_TABLE
-char *re_syntax_table;
+extern char *re_syntax_table;
#else /* not SYNTAX_TABLE */
-static char re_syntax_table[256];
-static void init_syntax_once P((void));
+/* 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 ()
@@ -113,7 +103,7 @@ init_syntax_once ()
if (done)
return;
- memset (re_syntax_table, 0, sizeof re_syntax_table);
+ bzero (re_syntax_table, sizeof re_syntax_table);
for (c = 'a'; c <= 'z'; c++)
re_syntax_table[c] = Sword;
@@ -123,1504 +113,2900 @@ init_syntax_once ()
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;
+
+ re_syntax_table['_'] = Sword;
done = 1;
}
-#endif /* SYNTAX_TABLE */
-#undef P
-#endif /* emacs */
+#endif /* not SYNTAX_TABLE */
+#define SYNTAX(c) re_syntax_table[c]
-/* Sequents are missing isgraph. */
-#ifndef isgraph
-#define isgraph(c) (isprint((c)) && !isspace((c)))
-#endif
-
+#endif /* not emacs */
+
/* Get the interface, including the syntax bits. */
#include "regex.h"
+/* isalpha etc. are used for the character classes. */
+#include <ctype.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.
+/* Jim Meyering writes:
+
+ "... Some ctype macros are valid only for character codes that
+ isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+ using /bin/cc or gcc but without giving an ansi option). So, all
+ ctype uses should be through macros like ISPRINT... If
+ STDC_HEADERS is defined, then autoconf has verified that the ctype
+ macros don't need to be guarded with references to isascii. ...
+ Defining isascii to 1 should let any compiler worth its salt
+ eliminate the && through constant folding." */
+#if ! defined (isascii) || defined (STDC_HEADERS)
+#undef 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.
- The value of `exactn' is needed in search.c (search_buffer) in emacs.
+ 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. */
-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. */
- };
-
+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,
-/* 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. */
+ /* 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. */
-#ifndef NFAILURES
-#define NFAILURES 80
-#endif
+#ifdef emacs
+ ,before_dot, /* Succeeds if before point. */
+ at_dot, /* Succeeds if at point. */
+ after_dot, /* Succeeds if after point. */
-#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
-
+ /* 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) \
- { (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; }
+ 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 contingous bytes starting
+/* Put into DESTINATION a number stored in two contiguous bytes starting
at SOURCE. */
+
#define EXTRACT_NUMBER(destination, source) \
- { (destination) = *(source) & 0377; \
- (destination) += SIGN_EXTEND_CHAR (*(char *)((source) + 1)) << 8; }
+ do { \
+ (destination) = *(source) & 0377; \
+ (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \
+ } while (0)
+
+#ifdef DEBUG
+static void extract_number _RE_ARGS((int *dest, unsigned char *source));
+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. */
-/* 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; }
+ do { \
+ EXTRACT_NUMBER (destination, source); \
+ (source) += 2; \
+ } while (0)
+
+#ifdef DEBUG
+static void extract_number_and_incr _RE_ARGS((int *destination,
+ unsigned char **source));
+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 */
-/* 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. */
+#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. */
-long
-re_set_syntax (syntax)
- long syntax;
+#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;
{
- long ret;
+ 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');
+}
- ret = obscure_syntax;
- obscure_syntax = syntax;
- return ret;
+
+/* 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)
+ {
+ printf ("%d:\t", p - start);
+
+ 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, last = -100;
+ register int in_range = 0;
+
+ printf ("/charset [%s",
+ (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
+
+ assert (p + *p < pend);
+
+ for (c = 0; c < 256; c++)
+ if (c / 8 < *p
+ && (p[1 + (c/8)] & (1 << (c % 8))))
+ {
+ /* Are we starting a range? */
+ if (last + 1 == c && ! in_range)
+ {
+ putchar ('-');
+ in_range = 1;
+ }
+ /* Have we broken a range? */
+ else if (last + 1 != c && in_range)
+ {
+ printchar (last);
+ in_range = 0;
+ }
+
+ if (! in_range)
+ printchar (c);
+
+ last = c;
+ }
+
+ if (in_range)
+ printchar (last);
+
+ putchar (']');
+
+ 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 to %d", p + mcnt - start);
+ break;
+
+ case on_failure_keep_string_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/on_failure_keep_string_jump to %d", p + mcnt - start);
+ break;
+
+ case dummy_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/dummy_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case push_dummy_failure:
+ printf ("/push_dummy_failure");
+ break;
+
+ case maybe_pop_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/maybe_pop_jump to %d", p + mcnt - start);
+ break;
+
+ case pop_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/pop_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case jump_past_alt:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump_past_alt to %d", p + mcnt - start);
+ break;
+
+ case jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump to %d", p + mcnt - start);
+ break;
+
+ case succeed_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/succeed_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case jump_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/jump_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case set_number_at:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/set_number_at location %d to %d", p + mcnt - start, 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));
+ }
+
+ putchar ('\n');
+ }
+
+ printf ("%d:\tend of pattern.\n", p - start);
+}
+
+
+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]);
+ }
}
-/* Set by re_set_syntax to the current regexp syntax to recognize. */
-long obscure_syntax = 0;
+#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 */
-/* Macros for re_compile_pattern, which is found below these definitions. */
+/* 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;
-#define CHAR_CLASS_MAX_LENGTH 6
-/* Fetch the next character in the uncompiled pattern, translating it if
- necessary. */
+/* 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 reg_errcode_t regex_compile _RE_ARGS((const char *pattern, size_t size,
+ reg_syntax_t syntax,
+ struct re_pattern_buffer *bufp));
+static void store_op1 _RE_ARGS((re_opcode_t op, unsigned char *loc, int arg));
+static void store_op2 _RE_ARGS((re_opcode_t op, unsigned char *loc,
+ int arg1, int arg2));
+static void insert_op1 _RE_ARGS((re_opcode_t op, unsigned char *loc,
+ int arg, unsigned char *end));
+static void insert_op2 _RE_ARGS((re_opcode_t op, unsigned char *loc,
+ int arg1, int arg2, unsigned char *end));
+static boolean at_begline_loc_p _RE_ARGS((const char *pattern, const char *p,
+ reg_syntax_t syntax));
+static boolean at_endline_loc_p _RE_ARGS((const char *p, const char *pend,
+ reg_syntax_t syntax));
+static reg_errcode_t compile_range _RE_ARGS((const char **p_ptr,
+ const char *pend,
+ char *translate,
+ reg_syntax_t syntax,
+ unsigned char *b));
+
+/* 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) \
- {if (p == pend) goto end_of_pattern; \
- c = * (unsigned char *) p++; \
- if (translate) c = translate[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) \
- {if (p == pend) goto end_of_pattern; \
- c = * (unsigned char *) p++; }
+ 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 28
+#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; \
- }
+ 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) \
- { \
+/* 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++ = (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; \
- }
+ *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, (int)((to) - (loc) - 3))
+
+/* Likewise, for a two-argument jump. */
+#define STORE_JUMP2(op, loc, to, arg) \
+ store_op2 (op, loc, (int)((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, (int)((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, (int)((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. */
+/* Any other compiler which, like MSC, has allocation limit below 2^16
+ bytes will have to use approach similar to what was done below for
+ MSC and drop MAX_BUF_SIZE a bit. Otherwise you may end up
+ reallocating to 0 bytes. Such thing is not going to work too well.
+ You have been warned!! */
+#ifdef _MSC_VER
+/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes.
+ The REALLOC define eliminates a flurry of conversion warnings,
+ but is not required. */
+#define MAX_BUF_SIZE 65500L
+#define REALLOC(p,s) realloc((p), (size_t) (s))
+#else
+#define MAX_BUF_SIZE (1L << 16)
+#define REALLOC realloc
+#endif
-/* Set the bit for character C in a character set list. */
-#define SET_LIST_BIT(c) (b[(c) / BYTEWIDTH] |= 1 << ((c) % BYTEWIDTH))
+/* 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)
-/* 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 (); */
+/* 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;
-/* 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.
+/* Macros for the compile stack. */
- 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. */
+/* 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. */
+/* int may be not enough when sizeof(int) == 2 */
+typedef long pattern_offset_t;
-char *
-re_compile_pattern (pattern, size, bufp)
- char *pattern;
- size_t size;
- struct re_pattern_buffer *bufp;
+typedef struct
{
- 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;
+ 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;
- /* 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;
+typedef struct
+{
+ compile_stack_elt_t *stack;
+ unsigned size;
+ unsigned avail; /* Offset of next open position. */
+} compile_stack_type;
- /* Address of start of the most recently finished expression.
- This tells postfix * where to find the start of its operand. */
- char *laststart = 0;
+#define INIT_COMPILE_STACK_SIZE 32
- /* In processing a repeat, 1 means zero matches is allowed. */
+#define COMPILE_STACK_EMPTY (compile_stack.avail == 0)
+#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size)
- char zero_times_ok;
+/* The next available element. */
+#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
- /* In processing a repeat, 1 means many matches is allowed. */
- char many_times_ok;
+/* Set the bit for character C in a list. */
+#define SET_LIST_BIT(c) \
+ (b[((unsigned char) (c)) / BYTEWIDTH] \
+ |= 1 << (((unsigned char) c) % BYTEWIDTH))
- /* Address of beginning of regexp, or inside of last \(. */
- char *begalt = b;
+/* 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"))
+
+static boolean group_in_compile_stack _RE_ARGS((compile_stack_type
+ compile_stack,
+ regnum_t regnum));
+
+/* `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. */
- /* In processing an interval, at least this many matches must be made. */
- int lower_bound;
+static reg_errcode_t
+regex_compile (pattern, size, syntax, bufp)
+ const char *pattern;
+ size_t 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;
- /* In processing an interval, at most this many matches can be made. */
- int upper_bound;
+ /* 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;
- /* Place in pattern (i.e., the {) to which to go back if the interval
- is invalid. */
- char *beg_interval = 0;
+ /* Points to the current (ending) position in the pattern. */
+ const char *p = pattern;
+ const char *pend = pattern + size;
- /* 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. */
+ /* How to translate the characters in the pattern. */
+ char *translate = bufp->translate;
- int stackb[40];
- int *stackp = stackb;
- int *stacke = stackb + 40;
- int *stackt;
+ /* 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;
- /* Counts \('s as they are encountered. Remembered for the matching \),
- where it becomes the register number to put in the stop_memory
- command. */
+ /* 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;
- int regnum = 1;
+ /* 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;
-#ifndef emacs
-#ifndef SYNTAX_TABLE
+ /* 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
+ init_syntax_once ();
#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);
+ { /* 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 = (char *) malloc (INIT_BUF_SIZE);
- if (!bufp->buffer) goto memory_exhausted;
- begalt = b = bufp->buffer;
+ { /* 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 '$':
- {
- 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 '^':
+ {
+ 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;
}
- 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;
+ 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 ((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)
+ 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 (obscure_syntax & RE_CONTEXTUAL_INVALID_OPS)
- goto invalid_pattern;
- else if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
- goto normal_char;
+ if (syntax & RE_CONTEXT_INVALID_OPS)
+ return REG_BADRPT;
+ else if (!(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;
+ {
+ /* 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;
+ }
- /* 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;
- }
+ /* 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 ('.')
+ && zero_times_ok
+ && 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;
- BUFPUSH (anychar);
- break;
+ laststart = b;
+ BUF_PUSH (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;
+ {
+ boolean had_char_class = false;
- 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');
+ 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);
- /* 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);
- }
+ 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++;
- /* 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];
+ /* 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 (! (obscure_syntax & RE_NO_BK_PARENS))
- goto normal_char;
- else
- goto handle_open;
+ 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 ')':
- 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;
+ if (syntax & RE_NEWLINE_ALT)
+ goto handle_alt;
+ else
+ goto normal_char;
+
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;
+ if (syntax & RE_NO_BK_VBAR)
+ goto handle_alt;
+ else
+ goto normal_char;
- case '{':
- if (! ((obscure_syntax & RE_NO_BK_CURLY_BRACES)
- && (obscure_syntax & RE_INTERVALS)))
- goto normal_char;
- else
+
+ case '{':
+ if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
goto handle_interval;
-
+ else
+ goto normal_char;
+
+
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);
+ 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);
+ }
- /* Leave space for a jump after previous alternative---to be
- filled in later. */
- fixup_jump = b;
- b += 3;
+ compile_stack.avail++;
+ fixup_alt_jump = 0;
laststart = 0;
- begalt = b;
- break;
+ begalt = b;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+ 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;
+
+ 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);
}
- /* 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;
+
+ /* 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;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+
+ /* 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;
- 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;
- }
+ *inner_group_loc = regnum - this_group_regnum;
+ BUF_PUSH_3 (stop_memory, this_group_regnum,
+ regnum - this_group_regnum);
+ }
+ }
+ break;
- /* 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;
- }
+ 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;
- beg_interval = 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. */
- if (beg_interval)
- p = beg_interval;
- else
+ /* 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))
{
- fprintf (stderr,
- "regex: no interval beginning to which to backtrack.\n");
- exit (1);
+ if (p > pattern && p[-1] == '\\')
+ goto normal_backslash;
}
-
- beg_interval = 0;
- PATFETCH (c); /* normal_char expects char in `c'. */
- goto normal_char;
- break;
+ goto normal_char;
#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;
+ /* 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;
- 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)
+
+ case 'w':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ laststart = b;
+ BUF_PUSH (wordchar);
+ break;
+
+
+ case 'W':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ laststart = b;
+ BUF_PUSH (notwordchar);
+ break;
+
+
+ case '<':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (wordbeg);
+ break;
+
+ case '>':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (wordend);
+ break;
+
+ case 'b':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (wordbound);
+ break;
+
+ case 'B':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (notwordbound);
+ break;
+
+ case '`':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ BUF_PUSH (begbuf);
+ break;
+
+ case '\'':
+ if (re_syntax_options & RE_NO_GNU_OPS)
+ goto normal_char;
+ 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)
- {
- if (obscure_syntax & RE_NO_EMPTY_BK_REF)
- goto invalid_pattern;
- else
- goto normal_char;
- }
+
+ if (c1 > regnum)
+ return REG_ESUBREG;
+
/* 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;
+ if (group_in_compile_stack (compile_stack, (regnum_t)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_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;
+ 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:
- 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)
+ /* 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 == '?'))
- || ((obscure_syntax & RE_INTERVALS)
- && ((obscure_syntax & RE_NO_BK_CURLY_BRACES)
+ || ((syntax & RE_INTERVALS)
+ && ((syntax & RE_NO_BK_BRACES)
? *p == '{'
: (p[0] == '\\' && p[1] == '{'))))
{
- laststart = b;
- BUFPUSH (exactn);
- pending_exact = b;
- BUFPUSH (0);
- }
- BUFPUSH (c);
- (*pending_exact)++;
- }
- }
+ /* 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 (fixup_jump)
- store_jump (fixup_jump, jump, b);
+ if (!COMPILE_STACK_EMPTY)
+ return REG_EPAREN;
- if (stackp != stackb) goto unmatched_open;
+ free (compile_stack.stack);
+ /* We have succeeded; set the length of the buffer. */
bufp->used = b - bufp->buffer;
- return 0;
- invalid_pattern:
- return "Invalid regular expression";
+#ifdef DEBUG
+ if (debug)
+ {
+ DEBUG_PRINT1 ("\nCompiled pattern: \n");
+ print_compiled_pattern (bufp);
+ }
+#endif /* DEBUG */
- unmatched_open:
- return "Unmatched \\(";
+ return REG_NOERROR;
+} /* regex_compile */
+
+/* Subroutines for `regex_compile'. */
- unmatched_close:
- return "Unmatched \\)";
+/* Store OP at LOC followed by two-byte integer parameter ARG. */
- end_of_pattern:
- return "Premature end of regular expression";
+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);
+}
- nesting_too_deep:
- return "Nesting too deep";
- too_big:
- return "Regular expression too big";
+/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */
- memory_exhausted:
- return "Memory exhausted";
+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);
}
-/* 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. */
+/* 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
-store_jump (from, opcode, to)
- char *from, *to;
- int opcode;
+insert_op1 (op, loc, arg, end)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg;
+ unsigned char *end;
{
- from[0] = (char)opcode;
- STORE_NUMBER(from + 1, to - (from + 3));
-}
+ register unsigned char *pfrom = end;
+ register unsigned char *pto = end + 3;
+ while (pfrom != loc)
+ *--pto = *--pfrom;
+
+ store_op1 (op, loc, arg);
+}
-/* 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. */
+/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */
static void
-insert_jump (op, from, to, current_end)
- int op;
- char *from, *to, *current_end;
+insert_op2 (op, loc, arg1, arg2, end)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg1, arg2;
+ unsigned char *end;
{
- register char *pfrom = current_end; /* Copy from here... */
- register char *pto = current_end + 3; /* ...to here. */
+ register unsigned char *pfrom = end;
+ register unsigned char *pto = end + 5;
- while (pfrom != from)
+ while (pfrom != loc)
*--pto = *--pfrom;
- store_jump (from, op, to);
+
+ store_op2 (op, loc, arg1, arg2);
}
-/* Store a jump of the form <opcode> <relative address> <n> .
+/* 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 ^. */
- 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 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));
+}
-static void
-store_jump_n (from, opcode, to, n)
- char *from, *to;
- int opcode;
- unsigned n;
+
+/* 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;
+ reg_syntax_t syntax;
{
- from[0] = (char)opcode;
- STORE_NUMBER (from + 1, to - (from + 3));
- STORE_NUMBER (from + 3, n);
+ 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 == '|');
}
-/* 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.
+/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
+ false if it's not. */
- If you call this function, you must zero out pending_exact. */
+static boolean
+group_in_compile_stack (compile_stack, regnum)
+ compile_stack_type compile_stack;
+ regnum_t regnum;
+{
+ int this_element;
-static void
-insert_jump_n (op, from, to, current_end, n)
- int op;
- char *from, *to, *current_end;
- unsigned n;
+ 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;
{
- register char *pfrom = current_end; /* Copy from here... */
- register char *pto = current_end + 5; /* ...to here. */
+ unsigned this_char;
- while (pfrom != from)
- *--pto = *--pfrom;
- store_jump_n (from, op, to, n);
+ 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
-/* 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.
+/* 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;
- If you call this function, you must zero out pending_exact. */
+typedef const unsigned char *fail_stack_elt_t;
-static void
-insert_op_2 (op, there, current_end, num_1, num_2)
- int op;
- char *there, *current_end;
- int num_1, num_2;
+typedef struct
{
- register char *pfrom = current_end; /* Copy from here... */
- register char *pto = current_end + 5; /* ...to here. */
+ fail_stack_elt_t *stack;
+ unsigned size;
+ unsigned avail; /* Offset of next open position. */
+} fail_stack_type;
- while (pfrom != there)
- *--pto = *--pfrom;
-
- there[0] = (char)op;
- STORE_NUMBER (there + 1, num_1);
- STORE_NUMBER (there + 3, num_2);
-}
+#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. */ \
+ /* Can't be int, since there is not a shred of a guarantee that int \
+ is wide enough to hold a value of something to which pointer can \
+ be assigned */ \
+ s_reg_t 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);\
+ }
+
+#define PUSH_FAILURE_POINT2(pattern_place, string_place, failure_code) \
+ /* Push the info, starting with the registers. */ \
+ DEBUG_PRINT1 ("\n"); \
+ \
+ PUSH_FAILURE_POINT_LOOP (); \
+ \
+ 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)
+
+/* Pulled out of PUSH_FAILURE_POINT() to shorten the definition
+ of that macro. (for VAX C) */
+#define PUSH_FAILURE_POINT_LOOP() \
+ 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); \
+ }
+
+/* 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;) \
+ s_reg_t 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); \
+ \
+ POP_FAILURE_POINT2 (low_reg, high_reg, regstart, regend, reg_info);
+/* Pulled out of POP_FAILURE_POINT() to shorten the definition
+ of that macro. (for MSC 5.1) */
+#define POP_FAILURE_POINT2(low_reg, high_reg, regstart, regend, reg_info) \
+ \
+ /* Restore register info. */ \
+ high_reg = (active_reg_t) POP_FAILURE_ITEM (); \
+ DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \
+ \
+ low_reg = (active_reg_t) 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 */
-/* 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.
+/* 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.
- The other components of bufp describe the pattern to be used. */
+ 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.
-void
+ Returns 0 if we succeed, -2 if an internal error. */
+
+int
re_compile_fastmap (bufp)
struct re_pattern_buffer *bufp;
{
- unsigned char *pattern = (unsigned char *) bufp->buffer;
- int size = bufp->used;
+ 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;
- 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;
+ unsigned char *pattern = bufp->buffer;
+ const unsigned char *p = pattern;
+ register unsigned char *pend = pattern + bufp->used;
-#ifndef NO_ALLOCA
- unsigned char *stackb[NFAILURES];
- unsigned char **stackp = stackb;
+ /* 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;
-#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;
+ /* 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)
+ while (p != pend || !FAIL_STACK_EMPTY ())
{
- is_a_succeed_n = 0;
if (p == pend)
- {
- bufp->can_be_null = 1;
- break;
+ {
+ 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) ((enum regexpcode) *p++))
+ switch ((int) ((re_opcode_t) *p++))
#else
- switch ((enum regexpcode) *p++)
+ 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:
- if (translate)
- fastmap[translate[p[1]]] = 1;
- else
- fastmap[p[1]] = 1;
+ fastmap[p[1]] = 1;
break;
- case begline:
- case before_dot:
+
+ 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 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 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 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)
+
+ /* 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 (stackp != stackb && *stackp == p)
- stackp--;
- continue;
+ /* 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);
- *++stackp = p + j;
- if (is_a_succeed_n)
- EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */
- continue;
+
+ /* 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:
- is_a_succeed_n = 1;
/* Get to the number of times to succeed. */
p += 2;
- /* Increment p past the n for when k != 0. */
+
+ /* 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++;
- 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 start_memory:
+ case stop_memory:
+ p += 2;
+ continue;
- 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;
+ 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.
- 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;
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
- case unused: /* pacify gcc -Wall */
- break;
- }
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
- /* 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;
+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 = 0;
}
- FREE_AND_RETURN_VOID(stackb);
}
-
-
+/* 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 (pbufp, string, size, startpos, range, regs)
- struct re_pattern_buffer *pbufp;
- char *string;
+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 (pbufp, (char *) 0, 0, string, size, startpos, range,
+ return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
regs, size);
}
-/* Using the compiled pattern in PBUFP->buffer, first tries to match the
+/* 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. 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.
+ 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 PBUFP->buffer and its contained
- subexpressions. Do not consider matching one past the index MSTOP in
- the virtual concatenation of STRING1 and STRING2.
+ 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.
- 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). */
+ 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 (pbufp, string1, size1, string2, size2, startpos, range,
- regs, mstop)
- struct re_pattern_buffer *pbufp;
- char *string1, *string2;
+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;
- register int range;
+ int range;
struct re_registers *regs;
- int mstop;
+ int stop;
{
- register char *fastmap = pbufp->fastmap;
- register unsigned char *translate = (unsigned char *) pbufp->translate;
+ int val;
+ register char *fastmap = bufp->fastmap;
+ register char *translate = bufp->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)
+ /* Check for out-of-range STARTPOS. */
+ 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. */
+ /* 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;
- /* 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)
+ 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;
@@ -1628,65 +3014,68 @@ re_search_2 (pbufp, string1, size1, string2, size2, startpos, range,
range = 1;
}
- while (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 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)
+ 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;
- 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]);
+ 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--;
- 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];
+ register char c = (size1 == 0 || startpos >= size1
+ ? string2[startpos - size1]
+ : string1[startpos]);
- c &= 0xff;
- if (translate ? !fastmap[translate[c]] : !fastmap[c])
+ if (!fastmap[(unsigned char) TRANSLATE (c)])
goto advance;
}
}
- if (range >= 0 && startpos == total_size
- && fastmap && pbufp->can_be_null == 0)
+ /* 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 (pbufp, string1, size1, string2, size2, startpos,
- regs, mstop);
+ val = re_match_2 (bufp, string1, size1, string2, size2,
+ startpos, regs, stop);
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;
@@ -1702,245 +3091,236 @@ re_search_2 (pbufp, string1, size1, string2, size2, startpos, range,
}
}
return -1;
-}
-
-
+} /* re_search_2 */
-#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. */
+/* 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.
-int re_max_failures = 2000;
-
-/* Routine used by re_match_2. */
-/* static int memcmp_translate (); *//* already declared */
-
+ 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. */
-/* Structure and accessing macros used in re_match_2: */
+/* Declarations and macros for re_match_2. */
-struct register_info
+typedef union
{
- 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. */ \
- }
-
+ 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)
+
+static boolean group_match_null_string_p _RE_ARGS((unsigned char **p,
+ unsigned char *end,
+ register_info_type *reg_info));
+static boolean alt_match_null_string_p _RE_ARGS((unsigned char *p,
+ unsigned char *end,
+ register_info_type *reg_info));
+static boolean common_op_match_null_string_p _RE_ARGS((unsigned char **p,
+ unsigned char *end,
+ register_info_type *reg_info));
+static int bcmp_translate _RE_ARGS((const char *s1, const char *s2,
+ int len, char *translate));
+
+/* 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 \
+ { \
+ active_reg_t 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)
-/* 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; \
+ }
-#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))\
+ 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. */
-/* 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.
+#ifndef emacs /* Emacs never uses this. */
+/* re_match is like re_match_2 except it takes only a single string. */
- If pbufp->fastmap is nonzero, then it had better be up to date.
+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 */
- 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. */
+/* 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 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
- struct re_pattern_buffer *pbufp;
- char *string1_arg, *string2_arg;
+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 mstop;
+ int stop;
{
- register unsigned char *p = (unsigned char *) pbufp->buffer;
-
- /* Pointer to beyond end of buffer. */
- register unsigned char *pend = p + pbufp->used;
+ /* General temporaries. */
+ int mcnt;
+ unsigned char *p1;
- 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. */
+ /* 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. */
- 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];
+ 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
- unsigned char **stackb;
- unsigned char **stackp;
- unsigned char **stacke;
+ /* We fill all the registers internally, independent of what we
+ return, for use in backreferences. The number here includes
+ an element for register zero. */
+ size_t num_regs = bufp->re_nsub + 1;
+
+ /* The currently active registers. */
+ active_reg_t lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ active_reg_t 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
@@ -1949,9 +3329,14 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
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];
+ const char **regstart = 0, **regend = 0;
+
+ /* 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 = 0, **old_regend = 0;
/* The is_active field of reg_info helps us keep track of which (possibly
nested) subexpressions we are currently in. The matched_something
@@ -1959,50 +3344,97 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
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];
-
+ register_info_type *reg_info = 0;
/* 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;
+ turn happens only if we have not yet matched the entire string. */
+ unsigned best_regs_set = false;
+ const char **best_regstart = 0, **best_regend = 0;
+
+ /* 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 = 0;
+ register_info_type *reg_info_dummy = 0;
+
+#ifdef DEBUG
+ /* Counts the total number of registers pushed. */
+ unsigned num_regs_pushed = 0;
#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
+ 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
- \( 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++)
+ 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] = (unsigned char *) (-1L);
+ 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;
}
- 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)
+ /* 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;
@@ -2013,66 +3445,73 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
end2 = string2 + size2;
/* Compute where to stop matching, within the two strings. */
- if (mstop <= size1)
+ if (stop <= size1)
{
- end_match_1 = string1 + mstop;
+ end_match_1 = string1 + stop;
end_match_2 = string2;
}
else
{
end_match_1 = end1;
- end_match_2 = string2 + mstop - size1;
+ 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
+ /* `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;
+ equal `string2'. */
+ if (size1 > 0 && pos <= size1)
+ {
+ d = string1 + pos;
+ dend = end_match_1;
+ }
else
- d = string2 + pos - size1, dend = end_match_2;
-
+ {
+ 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 match is complete, or it drops through if match fails
- at this starting point in the input data. */
-
- while (1)
+ function if the match is complete, or it drops through if the match
+ fails at this starting point in the input data. */
+ for (;;)
{
-#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. */
+ DEBUG_PRINT2 ("\n0x%x: ", p);
+
if (p == pend)
- {
- /* If not end of string, try backtracking. Otherwise done. */
+ { /* 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)
{
- if (stackp != stackb)
- {
- /* More failure points to try. */
-
- unsigned in_same_string =
- IS_IN_FIRST_STRING (best_regend[0])
- == MATCHING_IN_FIRST_STRING;
+ 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
- || (in_same_string && d > best_regend[0])
- || (! in_same_string && ! MATCHING_IN_FIRST_STRING))
+ if (!best_regs_set
+ || (same_str_p && d > match_end)
+ || (!same_str_p && !MATCHING_IN_FIRST_STRING))
{
- best_regs_set = 1;
- best_regend[0] = d; /* Never use regstart[0]. */
+ best_regs_set = true;
+ match_end = d;
- for (mcnt = 1; mcnt < RE_NREGS; mcnt++)
+ 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];
@@ -2080,123 +3519,395 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
}
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];
+ 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");
- for (mcnt = 0; mcnt < RE_NREGS; mcnt++)
+ 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, convert it
- to indices. */
- if (regs)
+ /* If caller wants register contents data back, do it. */
+ if (regs && !bufp->no_sub)
{
- 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++)
+ /* 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
{
- 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;
+ /* These braces fend off a "empty body in an else-statement"
+ warning under GCC when assert expands to nothing. */
+ assert (bufp->regs_allocated == REGS_FIXED);
}
- }
- FREE_AND_RETURN(stackb,
- (d - pos - (MATCHING_IN_FIRST_STRING ?
- string1 :
- string2 - size1)));
+
+ /* 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) ((enum regexpcode) *p++))
+ switch ((int) ((re_opcode_t) *p++))
#else
- switch ((enum regexpcode) *p++)
+ 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]));
- /* \( [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;
+ DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
+
IS_ACTIVE (reg_info[*p]) = 1;
MATCHED_SOMETHING (reg_info[*p]) = 0;
- p++;
+
+ /* 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;
- IS_ACTIVE (reg_info[*p]) = 0;
+ DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
- /* 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)
+ /* 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)
{
- register unsigned char *p2 = p + 1;
+ 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 (*p2++)
+ switch ((re_opcode_t) *p1++)
{
case jump_n:
- is_a_jump_n = 1;
- case finalize_jump:
- case maybe_finalize_jump:
+ is_a_jump_n = true;
+ case pop_failure_jump:
+ case maybe_pop_jump:
case jump:
case dummy_failure_jump:
- EXTRACT_NUMBER_AND_INCR (mcnt, p2);
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
if (is_a_jump_n)
- p2 += 2;
+ p1 += 2;
break;
+
+ default:
+ /* do nothing */ ;
}
- p2 += mcnt;
+ p1 += 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)
+ 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)
{
- EXTRACT_NUMBER_AND_INCR (mcnt, p2);
- PUSH_FAILURE_POINT (p2 + mcnt, d);
+ /* 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 ((s_reg_t) old_regend[r] >= (s_reg_t) regstart[r])
+ regend[r] = old_regend[r];
+ }
+ }
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
+ PUSH_FAILURE_POINT2(p1 + mcnt, d, -2);
+
goto fail;
}
}
- p++;
+
+ /* 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:
{
- int regno = *p++; /* Get which register to match against */
- register unsigned char *d2, *dend2;
+ register const char *d2, *dend2;
+ int regno = *p++; /* Get which register to match against. */
+ DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
- /* Where in input to try to start matching. */
+ /* 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
@@ -2204,10 +3915,10 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
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]))
+ dend2 = ((FIRST_STRING_P (regstart[regno])
+ == FIRST_STRING_P (regend[regno]))
? regend[regno] : end_match_1);
- while (1)
+ for (;;)
{
/* If necessary, advance to next segment in register
contents. */
@@ -2215,13 +3926,16 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
{
if (dend2 == end_match_2) break;
if (dend2 == regend[regno]) break;
- d2 = string2, dend2 = regend[regno]; /* end of string1 => advance to string2. */
+
+ /* 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;
+ PREFETCH ();
/* How many characters left in this segment to match. */
mcnt = dend - d;
@@ -2234,196 +3948,335 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
/* Compare that many; failure if mismatch, else move
past them. */
if (translate
- ? memcmp_translate (d, d2, mcnt, translate)
- : memcmp ((char *)d, (char *)d2, mcnt))
+ ? bcmp_translate (d, d2, mcnt, translate)
+ : bcmp (d, 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. */
+ /* 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;
- if (translate)
- c = translate[*d];
- else
- c = *d;
- if (c < *p * BYTEWIDTH
- && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
- not = !not;
+ /* endline is the dual of begline. */
+ case endline:
+ DEBUG_PRINT1 ("EXECUTING endline.\n");
- p += 1 + *p;
+ 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;
- 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))
+ /* Match at the very beginning of the data. */
+ case begbuf:
+ DEBUG_PRINT1 ("EXECUTING begbuf.\n");
+ if (AT_STRINGS_BEG (d))
break;
- else
- goto fail;
-
- case endline:
- if (d == end2
- || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n'))
+ 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;
+ 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. */
+ /* 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);
+ PUSH_FAILURE_POINT2(p + mcnt, NULL, -2);
+ break;
- /* A smart repeat is similar but loops back to the on_failure_jump
- so that each repetition makes another failure point. */
+ /* 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);
- PUSH_FAILURE_POINT (p + mcnt, d);
+ 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);
+ PUSH_FAILURE_POINT2(p + mcnt, d, -2);
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:
+
+ /* 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 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)
+
+ /* 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 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)
+ 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 = p1[3] == (unsigned char) charset_not;
- if (c < p1[4] * BYTEWIDTH
+ 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 1 if c would match. */
- /* That means it is not safe to finalize. */
+
+ /* `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) finalize_jump;
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
}
}
}
p -= 2; /* Point at relative address again. */
- if (p[-1] != (unsigned char) finalize_jump)
+ if ((re_opcode_t) p[-1] != pop_failure_jump)
{
- p[-1] = (unsigned char) jump;
- goto nofinalize;
+ p[-1] = (unsigned char) jump;
+ DEBUG_PRINT1 (" Match => jump.\n");
+ goto unconditional_jump;
}
/* 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. */
+ /* 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'. */
+ active_reg_t 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:
- nofinalize:
- EXTRACT_NUMBER_AND_INCR (mcnt, p);
- p += mcnt;
+ 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;
- 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;
+
+ /* 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);
+ PUSH_FAILURE_POINT2(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);
+ PUSH_FAILURE_POINT2(0, 0, -2);
+ break;
- /* Have to succeed matching what follows at least n times. Then
- just handle like an on_failure_jump. */
+ /* 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)
+ 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)
{
- p[2] = unused;
- p[3] = unused;
+ 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;
}
- else
- {
- fprintf (stderr, "regex: the succeed_n's n is not set.\n");
- exit (1);
- }
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 nofinalize; /* Do the jump without taking off
- any failure points. */
+ STORE_NUMBER (p + 2, mcnt);
+ goto unconditional_jump;
}
/* If don't have to jump any more, skip over the rest of command. */
else
@@ -2432,223 +4285,494 @@ re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
case set_number_at:
{
- register unsigned char *p1;
+ 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;
}
- /* 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)
+ DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+ if (AT_WORD_BOUNDARY (d))
break;
- goto fail;
+ goto fail;
case notwordbound:
- if (AT_WORD_BOUNDARY)
+ DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+ if (AT_WORD_BOUNDARY (d))
goto fail;
- break;
+ break;
case wordbeg:
- if (IS_A_LETTER (d) && (!IS_A_LETTER (d - 1) || AT_STRINGS_BEG))
+ DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
+ if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
break;
- goto fail;
+ 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))
+ DEBUG_PRINT1 ("EXECUTING wordend.\n");
+ if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
+ && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
break;
- goto fail;
+ goto fail;
#ifdef emacs
- case before_dot:
- if (PTR_CHAR_POS (d) >= point)
- goto fail;
- break;
-
+#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:
- if (PTR_CHAR_POS (d) != point)
+ DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
goto fail;
break;
-
- case after_dot:
- if (PTR_CHAR_POS (d) <= point)
- goto fail;
- break;
-
- case wordchar:
- mcnt = (int) Sword;
- goto matchsyntax;
+#endif /* not emacs19 */
case syntaxspec:
+ DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
mcnt = *p++;
- matchsyntax:
- PREFETCH;
- if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail;
- SET_REGS_MATCHED;
- break;
-
- case notwordchar:
+ goto matchsyntax;
+
+ case wordchar:
+ DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
mcnt = (int) Sword;
- goto matchnotsyntax;
+ 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++;
- matchnotsyntax:
- PREFETCH;
- if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail;
- SET_REGS_MATCHED;
+ 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:
- PREFETCH;
- if (!IS_A_LETTER (d))
+ DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
+ PREFETCH ();
+ if (!WORDCHAR_P (d))
goto fail;
- SET_REGS_MATCHED;
+ SET_REGS_MATCHED ();
+ d++;
break;
case notwordchar:
- PREFETCH;
- if (IS_A_LETTER (d))
+ DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
+ PREFETCH ();
+ if (WORDCHAR_P (d))
goto fail;
- SET_REGS_MATCHED;
- break;
-
- case before_dot:
- case at_dot:
- case after_dot:
- case syntaxspec:
- case notsyntaxspec:
+ SET_REGS_MATCHED ();
+ d++;
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;
+
+ default:
+ abort ();
}
continue; /* Successfully executed one pattern command; keep going. */
- /* Jump here if any matching operation fails. */
+
+ /* We goto here if a 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])
+ 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)
{
- POP_FAILURE_POINT ();
- goto fail;
+ 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 */ ;
+ }
}
- 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. */
- }
+ } /* for (;;) */
if (best_regs_set)
goto restore_best_regs;
- FREE_AND_RETURN(stackb,(-1)); /* Failure to match. */
-}
+ 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
-memcmp_translate (s1, s2, len, translate)
- unsigned char *s1, *s2;
+bcmp_translate (s1, s2, len, translate)
+ const char *s1, *s2;
register int len;
- unsigned char *translate;
+ char *translate;
{
- register unsigned char *p1 = s1, *p2 = s2;
+ register const unsigned char *p1 = (const unsigned char *) s1,
+ *p2 = (const unsigned char *) s2;
while (len)
{
- if (translate [*p1++] != translate [*p2++]) return 1;
+ 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;
+ size_t 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. */
+/* 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(GAWK)
+#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)
- char *s;
+ const char *s;
{
+ reg_errcode_t ret;
+
if (!s)
{
if (!re_comp_buf.buffer)
@@ -2658,197 +4782,289 @@ re_comp (s)
if (!re_comp_buf.buffer)
{
- if (!(re_comp_buf.buffer = (char *) malloc (200)))
- return "Memory exhausted";
+ re_comp_buf.buffer = (unsigned char *) malloc (200);
+ if (re_comp_buf.buffer == NULL)
+ return "Memory exhausted";
re_comp_buf.allocated = 200;
- if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH)))
+
+ re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
+ if (re_comp_buf.fastmap == NULL)
return "Memory exhausted";
}
- return re_compile_pattern (s, strlen (s), &re_comp_buf);
+
+ /* 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)
- char *s;
+ const char *s;
{
- int len = strlen (s);
- return 0 <= re_search (&re_comp_buf, s, len, 0, len,
- (struct re_registers *) 0);
+ const int len = strlen (s);
+ return
+ 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
}
-#endif /* not emacs && not GAWK */
+#endif /* not emacs and not _POSIX_SOURCE */
+
+/* POSIX.2 functions. Don't define these for Emacs. */
+#ifndef emacs
-
-#ifdef test
+/* regcomp takes a regular expression as a string and compiles it.
-#ifdef atarist
-long _stksize = 2L; /* reserve memory for stack */
-#endif
-#include <stdio.h>
+ PREG is a regex_t *. We do not expect any fields to be initialized,
+ since POSIX says we shouldn't. Thus, we set
-/* 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
- };
+ `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.
-#ifdef canned
+ PATTERN is the address of the pattern string.
-#include "tests.h"
+ CFLAGS is a series of bits which affect compilation.
-typedef enum { extended_test, basic_test } test_type;
+ If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+ use POSIX basic syntax.
-/* Use this to run the tests we've thought of. */
+ If REG_NEWLINE is set, then . and [^...] don't match newline.
+ Also, regexec will try a match beginning after every newline.
-void
-main ()
-{
- test_type t = extended_test;
+ 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.) */
- if (t == basic_test)
+int
+regcomp (preg, pattern, cflags)
+ regex_t *preg;
+ const char *pattern;
+ int cflags;
+{
+ reg_errcode_t ret;
+ reg_syntax_t 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;
+ preg->used = 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)
{
- printf ("Running basic tests:\n\n");
- test_posix_basic ();
+ 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 if (t == extended_test)
- {
- printf ("Running extended tests:\n\n");
- test_posix_extended ();
+ 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;
}
-#else /* not canned */
-/* Use this to run interactive tests. */
+/* 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. */
-void
-main (argc, argv)
- int argc;
- char **argv;
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+ const regex_t *preg;
+ const char *string;
+ size_t nmatch;
+ regmatch_t pmatch[];
+ int eflags;
{
- 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)
+ 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)
{
- gets (pat);
+ 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;
+ }
- if (*pat)
- {
- re_compile_pattern (pat, strlen(pat), &buf);
+ /* 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 (i = 0; i < buf.used; i++)
- printchar (buf.buffer[i]);
+ for (r = 0; r < nmatch; r++)
+ {
+ pmatch[r].rm_so = regs.start[r];
+ pmatch[r].rm_eo = regs.end[r];
+ }
+ }
- putchar ('\n');
+ /* If we needed the temporary register info, free the space now. */
+ free (regs.start);
+ free (regs.end);
+ }
- printf ("%d allocated, %d used.\n", buf.allocated, buf.used);
+ /* We want zero return to mean success, unlike `re_search'. */
+ return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
- 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 */
+/* Returns a message corresponding to an error code, ERRCODE, returned
+ from either regcomp or regexec. We don't use PREG here. */
- i = re_match (&buf, pat, strlen (pat), 0, 0);
- printf ("Match value %d.\n", i);
- }
-}
+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;
-#endif
+ 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 = re_error_msg[errcode];
-#ifdef NOTDEF
-print_buf (bufp)
- struct re_pattern_buffer *bufp;
-{
- int i;
+ /* POSIX doesn't require that we do anything in this case, but why
+ not be nice. */
+ if (! msg)
+ msg = "Success";
- 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);
+ msg_size = strlen (msg) + 1; /* Includes the null. */
- 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)
+ if (errbuf_size != 0)
{
- putchar ('\\');
- putchar (((c >> 6) & 3) + '0');
- putchar (((c >> 3) & 7) + '0');
- putchar ((c & 7) + '0');
+ if (msg_size > errbuf_size)
+ {
+ strncpy (errbuf, msg, errbuf_size - 1);
+ errbuf[errbuf_size - 1] = 0;
+ }
+ else
+ strcpy (errbuf, msg);
}
- else
- putchar (c);
+
+ return msg_size;
}
-error (string)
- char *string;
+
+/* Free dynamically allocated space used by PREG. */
+
+void
+regfree (preg)
+ regex_t *preg;
{
- puts (string);
- exit (1);
+ 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 /* test */
+
+#endif /* not emacs */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/gnu/usr.bin/awk/regex.h b/gnu/usr.bin/awk/regex.h
index fce11c3..757dbac 100644
--- a/gnu/usr.bin/awk/regex.h
+++ b/gnu/usr.bin/awk/regex.h
@@ -1,10 +1,11 @@
-/* Definitions for data structures callers pass the regex library.
+/* Definitions for data structures and routines for the regular
+ expression library, version 0.12.
- Copyright (C) 1985, 1989-90 Free Software Foundation, Inc.
+ Copyright (C) 1985, 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 1, or (at your option)
+ 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,
@@ -16,245 +17,489 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#ifndef __REGEXP_LIBRARY_H__
+#define __REGEXP_LIBRARY_H__
-#ifndef __REGEXP_LIBRARY
-#define __REGEXP_LIBRARY
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+ <regex.h>. */
-/* 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
+#ifdef VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+ should be there. */
+#include <stddef.h>
#endif
-#define BYTEWIDTH 8
+/* The following two types have to be signed and unsigned integer type
+ wide enough to hold a value of a pointer. For most ANSI compilers
+ ptrdiff_t and size_t should be likely OK. Still size of these two
+ types is 2 for Microsoft C. Ugh... */
+typedef long s_reg_t;
+typedef unsigned long active_reg_t;
-/* Maximum number of duplicates an interval can allow. */
-#ifndef RE_DUP_MAX
-#define RE_DUP_MAX ((1 << 15) - 1)
-#endif
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned long reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS (1L)
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
-/* 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:],
+/* 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_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions, of course).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+
+ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+ POSIX draft 11.2 says that * etc. in leading positions is undefined.
+ We already implemented a previous draft which made those constructs
+ invalid, though, so we haven't changed the code back. */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+ than the starting range point, as in [z-a], is invalid.
+ If not set, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, do not process the GNU regex operators.
+ IF not set, then the GNU regex operators are recognized. */
+#define RE_NO_GNU_OPS (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t re_syntax_options;
+
+/* Define combinations of the above bits for the standard possibilities.
+ (The [[[ comments delimit what gets put into the Texinfo file, so
+ don't delete them!) */
+/* [[[begin syntaxes]]] */
#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. */
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GNU_AWK \
+ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_SYNTAX_GNU_AWK | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
+ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
+ | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP \
+ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _RE_SYNTAX_POSIX_COMMON \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+ replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow. Some systems
+ (erroneously) define this in other header files, but we want our
+ value, so remove any previous define. */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+/* if sizeof(int) == 2, then ((1 << 15) - 1) overflows */
+#define RE_DUP_MAX (0x7fff)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp'). */
+
+/* If this bit is set, then use extended regular expression syntax.
+ If not set, then use basic regular expression syntax. */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+ characters in the string.
+ If not set, then anchors do match at newlines. */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+ If not set, then returns differ between not matching and errors. */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec). */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+ the beginning of the string (presumably because it's not the
+ beginning of a line).
+ If not set, then the beginning-of-line operator does match the
+ beginning of the string. */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line. */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Not implemented. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `no_sub' can be set. After the pattern has been
+ compiled, the `re_nsub' field is available. All other fields are
+ private to the regex routines. */
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. */
+{
+/* [[[begin pattern_buffer]]] */
+ /* Space that holds the compiled pattern. It is declared as
+ `unsigned char *' because its elements are
+ sometimes used as array indexes. */
+ unsigned char *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t syntax;
+
+ /* Pointer to a fastmap, if any, otherwise zero. re_search uses
+ the fastmap, if there is one, to skip over impossible
+ starting points for matches. */
+ char *fastmap;
+
+ /* Either a translate table to apply to all characters before
+ comparing them, or zero for no translation. The translation
+ is applied to a pattern when it is compiled and to a string
+ when it is matched. */
+ char *translate;
+
+ /* Number of subexpressions found by the compiler. */
+ size_t re_nsub;
+
+ /* Zero if this pattern cannot match the empty string, one else.
+ Well, in truth it's used only in `re_search_2', to see
+ whether or not we should use the fastmap, so we don't set
+ this absolutely perfectly; see `re_compile_fastmap' (the
+ `duplicate' case). */
+ unsigned can_be_null : 1;
+
+ /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+ for `max (RE_NREGS, re_nsub + 1)' groups.
+ If REGS_REALLOCATE, reallocate space if necessary.
+ If REGS_FIXED, use what's there. */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+ unsigned regs_allocated : 2;
+
+ /* Set to zero when `regex_compile' compiles a pattern; set to one
+ by `re_compile_fastmap' if it updates the fastmap. */
+ unsigned fastmap_accurate : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the
+ beginning of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+
+/* search.c (search_buffer) in Emacs needs this one opcode value. It is
+ defined both in `regex.c' and here. */
#define RE_EXACTN_VALUE 1
+
+/* Type for byte offsets within the string. POSIX mandates this. */
+typedef int regoff_t;
-/* 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.
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
- 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];
- };
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+ `re_match_2' returns information about at least this many registers
+ the first time a `regs' structure is passed. */
+#ifndef RE_NREGS
+#define RE_NREGS 30
+#endif
+/* POSIX specification for registers. Aside from the different names than
+ `re_registers', POSIX uses an array of structures, instead of a
+ structure of arrays. */
+typedef struct
+{
+ regoff_t rm_so; /* Byte offset from string's start to substring's start. */
+ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
+} regmatch_t;
+/* Declarations for routines. */
+
+/* To avoid duplicating every routine declaration -- once with a
+ prototype (if we are ANSI), and once without (if we aren't) -- we
+ use the following macro to declare argument types. This
+ unfortunately clutters up the declarations a bit, but I think it's
+ worth it. */
+
#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
+#define _RE_ARGS(args) args
-#else /* !__STDC__ */
+#else /* not __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();
+#define _RE_ARGS(args) ()
-#ifndef GAWK
-/* 4.2 bsd compatibility. */
-extern char *re_comp ();
-extern int re_exec ();
-#endif
+#endif /* not __STDC__ */
-#endif /* __STDC__ */
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+ You can also simply assign to the `re_syntax_options' variable. */
+extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+/* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `re_syntax_options', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+extern const char *re_compile_pattern
+ _RE_ARGS ((const char *pattern, size_t length,
+ struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+ compiled into BUFFER. Start searching at position START, for RANGE
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->no_sub are nonzero). */
+extern int re_search
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+extern int re_search_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, int range, struct re_registers *regs, int stop));
-#ifdef SYNTAX_TABLE
-extern char *re_syntax_table;
-#endif
-#endif /* !__REGEXP_LIBRARY */
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int re_match
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int re_match_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using BUFFER and REGS will use this memory
+ for recording register information. STARTS and ENDS must be
+ allocated with malloc, 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. */
+extern void re_set_registers
+ _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+ unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+/* 4.2 bsd compatibility. */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+
+/* POSIX compatibility. */
+extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
+extern int regexec
+ _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags));
+extern size_t regerror
+ _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
+ size_t errbuf_size));
+extern void regfree _RE_ARGS ((regex_t *preg));
+
+#endif /* not __REGEXP_LIBRARY_H__ */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/gnu/usr.bin/awk/version.c b/gnu/usr.bin/awk/version.c
index adea5fa..89b6cc0 100644
--- a/gnu/usr.bin/awk/version.c
+++ b/gnu/usr.bin/awk/version.c
@@ -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..923215e
--- /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..a9d2176
--- /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..ea91eaf
--- /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..a7bc9c7
--- /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..1e7dc1c
--- /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..e2b6007
--- /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..be4ab3a
--- /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..33827cc
--- /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..346b44a
--- /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..9938515
--- /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..fea9405
--- /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..59aa6e5
--- /dev/null
+++ b/gnu/usr.bin/bc/scan.c
@@ -0,0 +1,1368 @@
+/* A lexical scanner generated by flex */
+
+/* scanner skeleton version:
+ * $Header: /usr/fsys/odin/a/vern/flex/RCS/flex.skel,v 2.16 90/08/03 14:09:36 vern 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..1edd6e2
--- /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..954c719
--- /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..2fac3db
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/Makefile
@@ -0,0 +1,72 @@
+PROG = gdb
+BINDIR= /usr/bin
+SRCS = main.c blockframe.c breakpoint.c findvar.c stack.c thread.c \
+ source.c values.c eval.c valops.c valarith.c valprint.c printcmd.c \
+ symtab.c symfile.c symmisc.c infcmd.c infrun.c command.c utils.c \
+ expprint.c environ.c gdbtypes.c copying.c i386-tdep.c i386-pinsn.c \
+ freebsd-solib.c ser-unix.c exec.c fork-child.c infptrace.c inftarg.c \
+ corelow.c coredep.c freebsd-nat.c remote.c dcache.c remote-utils.c \
+ mem-break.c target.c putenv.c parse.c language.c buildsym.c \
+ objfiles.c minsyms.c maint.c demangle.c dbxread.c coffread.c \
+ elfread.c dwarfread.c mipsread.c stabsread.c core.c c-lang.c \
+ ch-lang.c m2-lang.c complaints.c typeprint.c c-typeprint.c \
+ ch-typeprint.c m2-typeprint.c c-valprint.c cp-valprint.c ch-valprint.c \
+ m2-valprint.c nlmread.c serial.c inflow.c regex.c init.c \
+ c-exp.tab.c ch-exp.tab.c m2-exp.tab.c version.c i386-dis.c dis-buf.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/usr/include/readline -I$(.CURDIR)/../bfd
+DPADD+= $(LIBREADLINE) $(LIBTERM)
+LDADD+= -lreadline -ltermcap
+
+.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..ccb216e
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/gdb.1
@@ -0,0 +1,371 @@
+.\" Copyright (c) 1991 Free Software Foundation
+.\" See section COPYING for conditions for redistribution
+.\" $Id: gdb.1,v 1.1.1.1 1993/10/30 21:59:13 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 "[\|" \-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 \-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..deb68eb
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c
@@ -0,0 +1,323 @@
+/* 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. */
+
+#include "defs.h"
+#include <machine/reg.h>
+
+/* this table must line up with REGISTER_NAMES in tm-i386.h */
+/* symbols like 'tEAX' come from <machine/reg.h> */
+static int tregmap[] =
+{
+ tEAX, tECX, tEDX, tEBX,
+ tESP, tEBP, tESI, tEDI,
+ tEIP, tEFLAGS, tCS, tSS
+};
+#ifdef sEAX
+static int sregmap[] =
+{
+ sEAX, sECX, sEDX, sEBX,
+ sESP, sEBP, sESI, sEDI,
+ sEIP, sEFLAGS, sCS, sSS
+};
+#endif
+/* 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;
+{
+ /* The following condition is a kludge to get at the proper register map
+ depending upon the state of pcb_flag.
+ The proper condition would be
+ if (u.u_pcb.pcb_flag & FM_TRAP)
+ but that would require a ptrace call here and wouldn't work
+ for corefiles. */
+
+#ifdef sEAX
+ if (blockend < 0x1fcc)
+ return (blockend + 4 * tregmap[regnum]);
+ else
+ return (blockend + 4 * sregmap[regnum]);
+#else
+ return (blockend + 4 * tregmap[regnum]);
+#endif
+}
+
+#ifdef FLOAT_INFO
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <a.out.h>
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/uio.h>
+#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */
+#include <sys/user.h>
+#undef curpcb
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/ptrace.h>
+
+#define fpstate save87
+#define U_FPSTATE(u) u.u_pcb.pcb_savefpu
+
+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 */
+}
+
+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");
+}
+
+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];
+};
+
+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);
+}
+
+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
+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 ("last exception: ");
+ 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 `p->regs.
+ */
+ st_regno = (fpreg + 8 - top) & 0x7;
+
+ 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);
+ }
+}
+
+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
+ {
+ printf("float info: can't do a core file (yet)\n");
+
+ return;
+#if 0
+ 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
+ }
+
+ print_387_status (0, (struct env387 *)buf);
+}
+
+#endif
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..a7af00f
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/i386/nm.h
@@ -0,0 +1,44 @@
+/* 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 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*
+
+#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..25b66c7
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/i386/tm.h
@@ -0,0 +1,76 @@
+/* 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. */
+
+/* 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. */
+#undef NUM_REGS
+#define NUM_REGS 10
+
+/* 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(FRAME)
+#define FRAME_SAVED_PC(FRAME) \
+ (((FRAME)->signal_handler_caller \
+ ? sigtramp_saved_pc (FRAME) \
+ : read_memory_integer ((FRAME)->frame + 4, 4)) \
+ )
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..d32e958
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/i386/version.c
@@ -0,0 +1,3 @@
+char *version = "4.11";
+char *host_canonical = "i386-unknown-freebsd";
+char *target_canonical = "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..8d28df0
--- /dev/null
+++ b/gnu/usr.bin/binutils/gdb/i386/xm.h
@@ -0,0 +1,31 @@
+/* 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
+
+/* Get rid of any system-imposed stack limit if possible. */
+
+#define SET_STACK_LIMIT_HUGE
diff --git a/gnu/usr.bin/cc/cccp/Makefile b/gnu/usr.bin/cc/cccp/Makefile
new file mode 100644
index 0000000..8467da4
--- /dev/null
+++ b/gnu/usr.bin/cc/cccp/Makefile
@@ -0,0 +1,12 @@
+#
+# $FreeBSD$
+#
+
+PROG = cpp
+SRCS = cccp.c cexp.c
+BINDIR= /usr/libexec
+LDDESTDIR+= -L${.CURDIR}/../cc_int/obj
+LDDESTDIR+= -L${.CURDIR}/../cc_int
+LDADD+= -lcc_int
+
+.include <bsd.prog.mk>
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..104fe3c
--- /dev/null
+++ b/gnu/usr.bin/cpio/Makefile
@@ -0,0 +1,9 @@
+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
+
+SRCS = copyin.c copyout.c copypass.c defer.c dstring.c fnmatch.c global.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..5196c5d
--- /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;
+ strcpy (tbuf, ctime (&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..f763f2b
--- /dev/null
+++ b/gnu/usr.bin/cpio/copyout.c
@@ -0,0 +1,801 @@
+/* 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 ();
+
+/* 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;
+ file_hdr.c_rdev_maj = major (file_stat.st_rdev);
+ file_hdr.c_rdev_min = minor (file_stat.st_rdev);
+ 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;
+ }
+
+ /* 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;
+}
diff --git a/gnu/usr.bin/cpio/copypass.c b/gnu/usr.bin/cpio/copypass.c
new file mode 100644
index 0000000..afd5753
--- /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..50b152c
--- /dev/null
+++ b/gnu/usr.bin/cpio/extern.h
@@ -0,0 +1,176 @@
+/* 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
+
+/* 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..5c94813
--- /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 __P
+#define __P(args) args
+#else /* Not C++ or ANSI C. */
+#undef __P
+#define __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 __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..dd9c366
--- /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/main.c b/gnu/usr.bin/cpio/main.c
new file mode 100644
index 0000000..78b5fc5
--- /dev/null
+++ b/gnu/usr.bin/cpio/main.c
@@ -0,0 +1,479 @@
+/* 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>
+#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 __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..bdf6829
--- /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/mt.1 b/gnu/usr.bin/cpio/mt.1
new file mode 100644
index 0000000..fc9cb64
--- /dev/null
+++ b/gnu/usr.bin/cpio/mt.1
@@ -0,0 +1,107 @@
+.TH MT 1L \" -*- nroff -*-
+.SH NAME
+mt \- control magnetic tape drive operation
+.SH SYNOPSIS
+.B mt
+[\-V] [\-f device] [\-\-file=device] [\-\-version]
+operation [count]
+.SH DESCRIPTION
+This manual page
+documents the GNU version of
+.BR mt .
+.B mt
+performs the given
+.IR operation ,
+which must be one of the tape operations listed below, on a tape
+drive.
+.PP
+The default tape device to operate on is taken from the file
+.I /usr/include/sys/mtio.h
+when
+.B mt
+is compiled. It can be overridden by giving a device file name in
+the environment variable
+.BR TAPE
+or by a command line option (see below), which also overrides the
+environment variable.
+.PP
+The device must be either a character special file or a
+remote tape drive. 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).
+.PP
+The available operations are listed below. Unique abbreviations are
+accepted. Not all operations are available on all systems, or work on
+all types of tape drives.
+Some operations optionally take a repeat count, which can be given
+after the operation name and defaults to 1.
+.IP "eof, weof"
+Write
+.I count
+EOF marks at current position.
+.IP fsf
+Forward space
+.I count
+files.
+The tape is positioned on the first block of the next file.
+.IP bsf
+Backward space
+.I count
+files.
+The tape is positioned on the first block of the next file.
+.IP fsr
+Forward space
+.I count
+records.
+.IP bsr
+Backward space
+.I count
+records.
+.IP bsfm
+Backward space
+.I count
+file marks.
+The tape is positioned on the beginning-of-the-tape side of
+the file mark.
+.IP asf
+Absolute space to file number
+.IR count .
+Equivalent to rewind followed by fsf
+.IR count .
+.IP eom
+Space to the end of the recorded media on the tape
+(for appending files onto tapes).
+.IP rewind
+Rewind the tape.
+.IP "offline, rewoffl"
+Rewind the tape and, if applicable, unload the tape.
+.IP status
+Print status information about the tape unit.
+.IP retension
+Rewind the tape, then wind it to the end of the reel,
+then rewind it again.
+.IP erase
+Erase the tape.
+.PP
+.B mt
+exits with a status of 0 if the operation succeeded, 1 if the
+operation or device name given was invalid, or 2 if the operation
+failed.
+.SS OPTIONS
+.TP
+.I "\-f, \-\-file=device"
+Use
+.I device
+as the file name of the tape drive to operate on.
+To use a
+tape drive on another machine, 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 "\-V, \-\-version"
+Print the version number of
+.BR mt .
diff --git a/gnu/usr.bin/cpio/rmt.c b/gnu/usr.bin/cpio/rmt.c
new file mode 100644
index 0000000..442a831
--- /dev/null
+++ b/gnu/usr.bin/cpio/rmt.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * rmt
+ */
+#include <stdio.h>
+#include <sgtty.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_GENTAPE_H /* e.g., ISC UNIX */
+#include <sys/gentape.h>
+#else
+#include <sys/mtio.h>
+#endif
+#include <errno.h>
+
+#if defined (_I386) && defined (_AIX)
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#else
+long lseek ();
+#endif
+
+#ifdef STDC_HEADERS
+#include <string.h>
+#include <stdlib.h>
+#else
+extern char *malloc ();
+#endif
+
+int tape = -1;
+
+char *record;
+int maxrecsize = -1;
+char *checkbuf ();
+void getstring ();
+void error ();
+
+#define SSIZE 64
+char device[SSIZE];
+char count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE];
+
+extern errno;
+extern char *sys_errlist[];
+char resp[BUFSIZ];
+
+FILE *debug;
+#define DEBUG(f) if (debug) fprintf(debug, f)
+#define DEBUG1(f,a) if (debug) fprintf(debug, f, a)
+#define DEBUG2(f,a1,a2) if (debug) fprintf(debug, f, a1, a2)
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int rval;
+ char c;
+ int n, i, cc;
+
+ argc--, argv++;
+ if (argc > 0)
+ {
+ debug = fopen (*argv, "w");
+ if (debug == 0)
+ exit (1);
+ (void) setbuf (debug, (char *) 0);
+ }
+top:
+ errno = 0;
+ rval = 0;
+ if (read (0, &c, 1) != 1)
+ exit (0);
+ switch (c)
+ {
+
+ case 'O':
+ if (tape >= 0)
+ (void) close (tape);
+ getstring (device);
+ getstring (mode);
+ DEBUG2 ("rmtd: O %s %s\n", device, mode);
+#if defined (i386) && defined (AIX)
+ /* This is alleged to fix a byte ordering problem. */
+ /* I'm quite suspicious if it's right. -- mib */
+ {
+ int oflag = atoi (mode);
+ int nflag = 0;
+ if ((oflag & 3) == 0)
+ nflag |= O_RDONLY;
+ if (oflag & 1)
+ nflag |= O_WRONLY;
+ if (oflag & 2)
+ nflag |= O_RDWR;
+ if (oflag & 0x0008)
+ nflag |= O_APPEND;
+ if (oflag & 0x0200)
+ nflag |= O_CREAT;
+ if (oflag & 0x0400)
+ nflag |= O_TRUNC;
+ if (oflag & 0x0800)
+ nflag |= O_EXCL;
+ tape = open (device, nflag, 0666);
+ }
+#else
+ tape = open (device, atoi (mode), 0666);
+#endif
+ if (tape < 0)
+ goto ioerror;
+ goto respond;
+
+ case 'C':
+ DEBUG ("rmtd: C\n");
+ getstring (device); /* discard */
+ if (close (tape) < 0)
+ goto ioerror;
+ tape = -1;
+ goto respond;
+
+ case 'L':
+ getstring (count);
+ getstring (pos);
+ DEBUG2 ("rmtd: L %s %s\n", count, pos);
+ rval = lseek (tape, (long) atoi (count), atoi (pos));
+ if (rval < 0)
+ goto ioerror;
+ goto respond;
+
+ case 'W':
+ getstring (count);
+ n = atoi (count);
+ DEBUG1 ("rmtd: W %s\n", count);
+ record = checkbuf (record, n);
+ for (i = 0; i < n; i += cc)
+ {
+ cc = read (0, &record[i], n - i);
+ if (cc <= 0)
+ {
+ DEBUG ("rmtd: premature eof\n");
+ exit (2);
+ }
+ }
+ rval = write (tape, record, n);
+ if (rval < 0)
+ goto ioerror;
+ goto respond;
+
+ case 'R':
+ getstring (count);
+ DEBUG1 ("rmtd: R %s\n", count);
+ n = atoi (count);
+ record = checkbuf (record, n);
+ rval = read (tape, record, n);
+ if (rval < 0)
+ goto ioerror;
+ (void) sprintf (resp, "A%d\n", rval);
+ (void) write (1, resp, strlen (resp));
+ (void) write (1, record, rval);
+ goto top;
+
+ case 'I':
+ getstring (op);
+ getstring (count);
+ DEBUG2 ("rmtd: I %s %s\n", op, count);
+#ifdef MTIOCTOP
+ {
+ struct mtop mtop;
+ mtop.mt_op = atoi (op);
+ mtop.mt_count = atoi (count);
+ if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0)
+ goto ioerror;
+ rval = mtop.mt_count;
+ }
+#endif
+ goto respond;
+
+ case 'S': /* status */
+ DEBUG ("rmtd: S\n");
+ {
+#ifdef MTIOCGET
+ struct mtget mtget;
+ if (ioctl (tape, MTIOCGET, (char *) &mtget) < 0)
+ goto ioerror;
+ rval = sizeof (mtget);
+ (void) sprintf (resp, "A%d\n", rval);
+ (void) write (1, resp, strlen (resp));
+ (void) write (1, (char *) &mtget, sizeof (mtget));
+#endif
+ goto top;
+ }
+
+ default:
+ DEBUG1 ("rmtd: garbage command %c\n", c);
+ exit (3);
+ }
+respond:
+ DEBUG1 ("rmtd: A %d\n", rval);
+ (void) sprintf (resp, "A%d\n", rval);
+ (void) write (1, resp, strlen (resp));
+ goto top;
+ioerror:
+ error (errno);
+ goto top;
+}
+
+void
+getstring (bp)
+ char *bp;
+{
+ int i;
+ char *cp = bp;
+
+ for (i = 0; i < SSIZE; i++)
+ {
+ if (read (0, cp + i, 1) != 1)
+ exit (0);
+ if (cp[i] == '\n')
+ break;
+ }
+ cp[i] = '\0';
+}
+
+char *
+checkbuf (record, size)
+ char *record;
+ int size;
+{
+ if (size <= maxrecsize)
+ return (record);
+ if (record != 0)
+ free (record);
+ record = malloc (size);
+ if (record == 0)
+ {
+ DEBUG ("rmtd: cannot allocate buffer space\n");
+ exit (4);
+ }
+ maxrecsize = size;
+#ifdef SO_RCVBUF
+ while (size > 1024 &&
+ setsockopt (0, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof (size)) < 0)
+ size -= 1024;
+#else
+ size = 1 + ((size - 1) % 1024);
+#endif
+ return (record);
+}
+
+void
+error (num)
+ int num;
+{
+
+ DEBUG2 ("rmtd: E %d (%s)\n", num, sys_errlist[num]);
+ (void) sprintf (resp, "E%d\n%s\n", num, sys_errlist[num]);
+ (void) write (1, resp, strlen (resp));
+}
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..16eeee0
--- /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..52e3e85
--- /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/Makefile b/gnu/usr.bin/cvs/Makefile
new file mode 100644
index 0000000..d75858b
--- /dev/null
+++ b/gnu/usr.bin/cvs/Makefile
@@ -0,0 +1,3 @@
+SUBDIR = lib cvs mkmodules
+
+.include <bsd.subdir.mk>
diff --git a/gnu/usr.bin/cvs/contrib/README b/gnu/usr.bin/cvs/contrib/README
new file mode 100644
index 0000000..412be26
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/README
@@ -0,0 +1,68 @@
+@(#)README 1.8 92/04/10
+
+This "contrib" directory is a place holder for code/scripts sent to
+me by contributors around the world. This READM file will be kept
+up-to-date from release to release. BUT, I must point out that these
+contributions are really, REALLY UNSSUPPORTED. 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.pl 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.pl A perl script, to be combined with log_accum.pl, to
+ log_accum.pl 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.
+ Also does 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.pl 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.pl 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>.
+ cvs_acls.pl 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.pl 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>
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..b353edc
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cln_hist.pl
@@ -0,0 +1,91 @@
+#!/usr/bin/perl -- # -*-Perl-*-
+#
+# cln_hist.pl,v 1.1 1992/04/10 03:04:15 berliner 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..b3f7e9a
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/commit_prep.pl
@@ -0,0 +1,168 @@
+#!/usr/local/bin/perl -w
+#
+#
+# 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_accumulate script. For new file, it forcing 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.
+#
+# Contributed by David Hampton <hampton@cisco.com>
+#
+
+############################################################
+#
+# Configurable options
+#
+############################################################
+#
+# Check each file (except dot files) for an RCS "Id" keyword.
+#
+$check_id = 1;
+
+#
+# Record the directory for later use by the log_accumulate stript.
+#
+$record_directory = 1;
+
+############################################################
+#
+# Constants
+#
+############################################################
+$LAST_FILE = "/tmp/#cvs.lastdir";
+$ENTRIES = "CVS/Entries";
+
+$NoId = "
+%s - Does not contain a line with the keyword \"Id:\".
+ Please see the template files for an example.\n";
+
+# Protect string from substitution by RCS.
+$NoName = "
+%s - The ID line should contain only \"\$\I\d\:\ \$\" 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.\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) || die("Cannot open $filename, stopped");
+ for ($i = 1; $i < 10; $i++) {
+ $pos = -1;
+ last if eof(FILE);
+ $line = <FILE>;
+ $pos = index($line, "Id: ");
+ last if ($pos >= 0);
+ }
+
+ if ($pos == -1) {
+ printf($NoId, $filename);
+ return(1);
+ }
+
+ ($id, $rname, $version) = split(' ', substr($line, $pos));
+ if ($cvsversion{$filename} == 0) {
+ if ($rname ne "\$") {
+ printf($NoName, $filename);
+ return(1);
+ }
+ return(0);
+ }
+
+ if ($rname ne "$filename,v") {
+ printf($BadName, $filename, substr($rname, 0, length($rname)-2));
+ return(1);
+ }
+ if ($cvsversion{$filename} < $version) {
+ printf($BadVersion, $filename, $filename, $cvsversion{$filename},
+ "newer", $version, $filename);
+ return(1);
+ }
+ if ($cvsversion{$filename} > $version) {
+ printf($BadVersion, $filename, $filename, $cvsversion{$filename},
+ "older", $version, $filename);
+ return(1);
+ }
+ return(0);
+}
+
+#############################################################
+#
+# Main Body
+#
+############################################################
+
+$id = getpgrp();
+#print("ARGV - ", join(":", @ARGV), "\n");
+#print("id - ", id, "\n");
+
+#
+# Suck in the 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;
+ $directory = $ARGV[0];
+ shift @ARGV;
+ foreach $arg (@ARGV) {
+ next if (index($arg, ".") == 0);
+ $failed += &check_version($arg);
+ }
+ if ($failed) {
+ print "\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_acls.pl b/gnu/usr.bin/cvs/contrib/cvs_acls.pl
new file mode 100644
index 0000000..1a0096a
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvs_acls.pl
@@ -0,0 +1,142 @@
+#!/usr/bin/perl -- # -*-Perl-*-
+#
+# cvs_acls.pl,v 1.2 1992/04/11 16:01:24 berliner 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 b/gnu/usr.bin/cvs/contrib/cvscheck
new file mode 100644
index 0000000..67fdbbd
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvscheck
@@ -0,0 +1,84 @@
+#! /bin/sh
+# cvscheck,v 1.2 1992/04/10 03:04:19 berliner 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/cvscheck.man b/gnu/usr.bin/cvs/contrib/cvscheck.man
new file mode 100644
index 0000000..10d47f5
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvscheck.man
@@ -0,0 +1,53 @@
+.\" cvscheck.man,v 1.1 1992/04/10 03:04:20 berliner 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/cvshelp.man b/gnu/usr.bin/cvs/contrib/cvshelp.man
new file mode 100644
index 0000000..a7128a8
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/cvshelp.man
@@ -0,0 +1,562 @@
+.\" cvshelp.man,v 1.1 1992/04/10 03:04:21 berliner 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 b/gnu/usr.bin/cvs/contrib/descend
new file mode 100644
index 0000000..b63e4a7
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/descend
@@ -0,0 +1,116 @@
+#! /bin/sh
+# descend,v 1.1 1992/04/03 05:22:52 berliner 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/descend.man b/gnu/usr.bin/cvs/contrib/descend.man
new file mode 100644
index 0000000..adeab3b
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/descend.man
@@ -0,0 +1,115 @@
+.\" descend.man,v 1.1 1992/04/03 05:22:53 berliner 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/dirfns b/gnu/usr.bin/cvs/contrib/dirfns
new file mode 100644
index 0000000..8324c41
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/dirfns
@@ -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/log.pl b/gnu/usr.bin/cvs/contrib/log.pl
new file mode 100644
index 0000000..a6c75f6
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/log.pl
@@ -0,0 +1,104 @@
+#!/usr/bin/perl
+
+# Modified by berliner@Sun.COM to add support for CVS 1.3 2/27/92
+#
+# Date: Tue, 6 Aug 91 13:27 EDT
+# From: samborn@sunrise.com (Kevin Samborn)
+#
+# I revised the perl script I sent you yesterday to use the info you
+# send in on stdin. (I am appending the newer script to the end)
+#
+# now the output looks like this:
+#
+# **************************************
+# date: Tuesday, August 6, 1991 @ 13:17
+# author: samborn
+# Update of /elmer/cvs/CVSROOT.adm
+# In directory astro:/home/samborn/CVSROOT.adm
+#
+# Modified Files:
+# test3
+#
+# Added Files:
+# test6
+#
+# Removed Files:
+# test4
+#
+# Log Message:
+# wow, what a test
+#
+# RCS: 1.4 /elmer/cvs/CVSROOT.adm/test3,v
+# RCS: 1.1 /elmer/cvs/CVSROOT.adm/test6,v
+# RCS: 1.1 /elmer/cvs/CVSROOT.adm/Attic/test4,v
+#
+
+#
+# turn off setgid
+#
+$) = $(;
+
+#
+# parse command line arguments
+#
+@files = split(/ /,$ARGV[0]);
+$logfile = $ARGV[1];
+$cvsroot = $ENV{'CVSROOT'};
+
+#
+# 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 login name
+#
+$login = getlogin || (getpwuid($<))[0] || "nobody";
+
+#
+# open log file for appending
+#
+if ((open(OUT, ">>" . $logfile)) != 1) {
+ die "Could not open logfile " . $logfile . "\n";
+}
+
+#
+# Header
+#
+print OUT "\n";
+print OUT "**************************************\n";
+print OUT "date: " . $days[$wday] . ", " . $mos[$mon] . " " . $mday . ", 19" . $year .
+ " @ " . $hour . ":" . sprintf("%02d", $min) . "\n";
+print OUT "author: " . $login . "\n";
+
+#
+#print the stuff on stdin to the logfile
+#
+open(IN, "-");
+while(<IN>) {
+ print OUT $_;
+}
+close(IN);
+
+print OUT "\n";
+
+#
+# after log information, do an 'cvs -Qn status' on each file in the arguments.
+#
+for $file (@files[1..$#files]) {
+ if ($file eq "-") {
+ last;
+ }
+ open(RCS,"-|") || exec 'cvs', '-Qn', 'status', $file;
+ while (<RCS>) {
+ if (substr($_, 0, 7) eq " RCS") {
+ print OUT;
+ }
+ }
+ close (RCS);
+}
+
+close (OUT);
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..798e25f
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/log_accum.pl
@@ -0,0 +1,331 @@
+#!/usr/local/bin/perl -w
+#
+# 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>
+#
+
+############################################################
+#
+# Configurable options
+#
+############################################################
+#
+# Do cisco Systems, Inc. specific nonsense.
+#
+$cisco_systems = 1;
+
+#
+# Recipient of all mail messages
+#
+$mailto = "sw-notification@cisco.com";
+
+############################################################
+#
+# Constants
+#
+############################################################
+$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";
+
+$VERSION_FILE = "version";
+$TRUNKREV_FILE = "TrunkRev";
+$CHANGES_FILE = "Changes";
+$CHANGES_TEMP = "Changes.tmp";
+
+############################################################
+#
+# Subroutines
+#
+############################################################
+
+sub format_names {
+ local($dir, @files) = @_;
+ local(@lines);
+ $lines[0] = sprintf(" %-08s", $dir);
+ foreach $file (@files) {
+ if (length($lines[$#lines]) + length($file) > 60) {
+ $lines[++$#lines] = sprintf(" %8s", " ");
+ }
+ $lines[$#lines] .= " ".$file;
+ }
+ @lines;
+}
+
+sub cleanup_tmpfiles {
+ local($all) = @_;
+ local($wd, @files);
+
+ $wd = `pwd`;
+ chdir("/tmp");
+ opendir(DIR, ".");
+ if ($all == 1) {
+ push(@files, grep(/$id$/, readdir(DIR)));
+ } else {
+ push(@files, grep(/^$FILE_PREFIX.*$id$/, readdir(DIR)));
+ }
+ closedir(DIR);
+ foreach (@files) {
+ unlink $_;
+ }
+ 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_file {
+ local($filename, $dir, @files) = @_;
+ if (@files) {
+ local(@lines) = &format_names($dir, @files);
+ open(FILE, ">>$filename") || die ("Cannot open file $filename.\n");
+ print(FILE join("\n", @lines), "\n");
+ close(FILE);
+ }
+}
+
+sub write_line {
+ local($filename, $line) = @_;
+ open(FILE, ">$filename") || die("Cannot open file $filename.\n");
+ print(FILE $line, "\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_file {
+ local(@text);
+ local($filename, $leader) = @_;
+ open(FILE, "<$filename") || return ();
+ while (<FILE>) {
+ chop;
+ push(@text, sprintf(" %-10s %s", $leader, $_));
+ $leader = "";
+ }
+ close(FILE);
+ @text;
+}
+
+sub read_logfile {
+ local(@text);
+ local($filename, $leader) = @_;
+ open(FILE, "<$filename") || die ("Cannot open log file $filename.\n");
+ while (<FILE>) {
+ chop;
+ push(@text, $leader.$_);
+ }
+ close(FILE);
+ @text;
+}
+
+sub bump_version {
+ local($trunkrev, $editnum, $version);
+
+ $trunkrev = &read_line("$ENV{'CVSROOT'}/$repository/$TRUNKREV_FILE");
+ $editnum = &read_line("$ENV{'CVSROOT'}/$repository/$VERSION_FILE");
+ &write_line("$ENV{'CVSROOT'}/$repository/$VERSION_FILE", $editnum+1);
+ $version = $trunkrev . "(" . $editnum . ")";
+}
+
+sub build_header {
+ local($version) = @_;
+ local($header);
+ local($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
+ $header = sprintf("%-8s %s %02d/%02d/%02d %02d:%02d:%02d",
+ $login, $version, $year%100, $mon+1, $mday,
+ $hour, $min, $sec);
+}
+
+sub do_changes_file {
+ local($changes, $tmpchanges);
+ local(@text) = @_;
+
+ $changes = "$ENV{'CVSROOT'}/$repository/$CHANGES_FILE";
+ $tmpchanges = "$ENV{'CVSROOT'}/$repository/$CHANGES_TEMP";
+ if (rename($changes, $tmpchanges) != 1) {
+ die("Cannot rename $changes to $tmpchanges.\n");
+ }
+ open(CHANGES, ">$changes") || die("Cannot open $changes.\n");
+ open(TMPCHANGES, "<$tmpchanges") || die("Cannot open $tmpchanges.\n");
+ print(CHANGES join("\n", @text), "\n\n");
+ print(CHANGES <TMPCHANGES>);
+ close(CHANGES);
+ close(TMPCHANGES);
+ unlink($tmpchanges);
+}
+
+sub mail_notification {
+ local($name, @text) = @_;
+ open(MAIL, "| mail -s \"Source Repository Modification\" $name");
+ print(MAIL join("\n", @text));
+ close(MAIL);
+}
+
+#############################################################
+#
+# Main Body
+#
+############################################################
+
+#
+# Initialize basic variables
+#
+$id = getpgrp();
+$state = $STATE_NONE;
+$login = getlogin || (getpwuid($<))[0] || die("Unknown user $<.\n");
+@files = split(' ', $ARGV[0]);
+@path = split('/', $files[0]);
+$repository = @path[0];
+if ($#path == 0) {
+ $dir = ".";
+} else {
+ $dir = join('/', @path[1..$#path]);
+}
+#print("ARGV - ", join(":", @ARGV), "\n");
+#print("files - ", join(":", @files), "\n");
+#print("path - ", join(":", @path), "\n");
+#print("dir - ", $dir, "\n");
+#print("id - ", $id, "\n");
+
+#
+# Check for a new directory first. This will always appear as a
+# single item in the argument list, and an empty log message.
+#
+if ($ARGV[0] =~ /New directory/) {
+ $version = &bump_version if ($cisco_systems != 0);
+ $header = &build_header($version);
+ @text = ();
+ push(@text, $header);
+ push(@text, "");
+ push(@text, " ".$ARGV[0]);
+ &do_changes_file(@text) if ($cisco_systems != 0);
+ &mail_notification($mailto, @text);
+ exit 0;
+}
+
+#
+# Iterate over the body of the message collecting information.
+#
+while (<STDIN>) {
+ chop; # Drop the newline
+ 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 space
+ s/[ \t\n]+$//; # delete trailing space
+
+ push (@changed_files, split) if ($state == $STATE_CHANGED);
+ push (@added_files, split) if ($state == $STATE_ADDED);
+ push (@removed_files, split) if ($state == $STATE_REMOVED);
+ push (@log_lines, $_) if ($state == $STATE_LOG);
+}
+
+#
+# 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);
+ }
+}
+
+#
+# Find the log file that matches this log message
+#
+for ($i = 0; ; $i++) {
+ last if (! -e "$LOG_FILE.$i.$id");
+ @text = &read_logfile("$LOG_FILE.$i.$id", "");
+ last if ($#text == -1);
+ last if (join(" ", @log_lines) eq join(" ", @text));
+}
+
+#
+# Spit out the information gathered in this pass.
+#
+&write_logfile("$LOG_FILE.$i.$id", @log_lines);
+&append_to_file("$ADDED_FILE.$i.$id", $dir, @added_files);
+&append_to_file("$CHANGED_FILE.$i.$id", $dir, @changed_files);
+&append_to_file("$REMOVED_FILE.$i.$id", $dir, @removed_files);
+
+#
+# Check whether this is the last directory. If not, quit.
+#
+$_ = &read_line("$LAST_FILE.$id");
+exit 0 if (! grep(/$files[0]$/, $_));
+
+#
+# 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.
+#
+# Get the full version number
+#
+$version = &bump_version if ($cisco_systems != 0);
+$header = &build_header($version);
+
+#
+# Produce the final compilation of the log messages
+#
+@text = ();
+push(@text, $header);
+push(@text, "");
+for ($i = 0; ; $i++) {
+ last if (! -e "$LOG_FILE.$i.$id");
+ push(@text, &read_file("$CHANGED_FILE.$i.$id", "Modified:"));
+ push(@text, &read_file("$ADDED_FILE.$i.$id", "Added:"));
+ push(@text, &read_file("$REMOVED_FILE.$i.$id", "Removed:"));
+ push(@text, " Log:");
+ push(@text, &read_logfile("$LOG_FILE.$i.$id", " "));
+ push(@text, "");
+}
+if ($cisco_systems != 0) {
+ @ddts = grep(/^CSCdi/, split(' ', join(" ", @text)));
+ $text[0] .= " " . join(" ", @ddts);
+}
+#
+# Put the log message at the beginning of the Changes file and mail
+# out the notification.
+#
+&do_changes_file(@text) if ($cisco_systems != 0);
+&mail_notification($mailto, @text);
+&cleanup_tmpfiles(1);
+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..74cc5e1
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/mfpipe.pl
@@ -0,0 +1,87 @@
+#!/usr/bin/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.
+#
+# mfpipe.pl,v 1.1 1992/03/02 01:22:41 berliner 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..fab9a7d
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog
@@ -0,0 +1,119 @@
+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..8c89053
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL
@@ -0,0 +1,83 @@
+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. 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.
+
+ 4. 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. Create the info file `pcl-cvs' 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), or you could use the preformatted
+ info file `pcl-cvs.info' that is included in the distribution
+ (type `cp pcl-cvs.info pcl-cvs').
+
+ 2. Move the info file `pcl-cvs' to your standard info directory.
+ This might be called something like `/usr/gnu/emacs/info'.
+
+ 3. Edit the file `dir' in the info directory and enter one line to
+ contain a pointer to the info file `pcl-cvs'. The line can, for
+ instance, look like this:
+
+ * Pcl-cvs: (pcl-cvs). An Emacs front-end to CVS.
+
+
+
+
+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..f0ded69
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile
@@ -0,0 +1,78 @@
+# Makefile,v 1.2 1992/04/07 20:49:07 berliner Exp
+# Makefile for pcl-cvs release 1.02.
+# Copyright (C) 1992 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.
+
+# This is the directory in which the ELFILES and ELCFILES will be
+# installed.
+
+lispdir = /usr/local/lib/elisp
+
+# Where to install the info file.
+
+prefix=/usr/local
+infodir = $(prefix)/info
+
+#
+# The rest of this file should not need to be modified.
+#
+
+# Just in case...
+SHELL = /bin/sh
+
+ELFILES = pcl-cvs.el cookie.el elib-dll.el elib-node.el
+ELCFILES = pcl-cvs.elc cookie.elc elib-dll.elc elib-node.elc
+INFOFILES = pcl-cvs
+TEXTMPS = pcl-cvs.aux pcl-cvs.log pcl-cvs.toc pcl-cvs.dvi pcl-cvs.cp \
+ pcl-cvs.fn pcl-cvs.vr pcl-cvs.tp pcl-cvs.ky pcl-cvs.pg \
+ pcl-cvs.cps pcl-cvs.fns pcl-cvs.kys pcl-cvs.pgs pcl-cvs.tps \
+ pcl-cvs.vrs
+
+INSTALL = install
+INSTALL_DATA = $(INSTALL)
+
+elcfiles:
+ emacs -batch -l ./compile-all.el -f compile-pcl-cvs
+
+all: elcfiles info
+
+# Don't install the info file yet, since it requires makeinfo
+# version 2.something (and version 1.something is distributed with emacs).
+#
+# install: install_elc install_info
+install: install_elc
+ for i in $(ELFILES); do $(INSTALL_DATA) $$i $(lispdir)/$$i; done
+
+install_elc: elcfiles
+ for i in $(ELCFILES); do $(INSTALL_DATA) $$i $(lispdir)/$$i; done
+
+install_info: pcl-cvs
+ $(INSTALL_DATA) pcl-cvs $(infodir)/pcl-cvs
+
+info pcl-cvs: pcl-cvs.texinfo
+ makeinfo +fill-column=70 pcl-cvs.texinfo
+
+pcl-cvs.dvi: pcl-cvs.texinfo
+ tex pcl-cvs.texinfo
+ -texindex pcl-cvs.cp pcl-cvs.fn pcl-cvs.vr pcl-cvs.tp pcl-cvs.ky \
+ pcl-cvs.pg
+ tex pcl-cvs.texinfo
+
+mostlyclean clean realclean:
+ rm -f *~ core $(ELCFILES) $(INFOFILES) $(TEXTMPS)
+
+tags TAGS:
+ etags *.el
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..6f0a5fe
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/README
@@ -0,0 +1,14 @@
+README,v 1.2 1992/04/07 20:49:09 berliner Exp
+
+This is the readme file for pcl-cvs, release 1.02.
+
+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
+2.14 a preformatted info file is also included (pcl-cvs.info).
+
+ ceder@lysator.liu.se
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..74f1bca
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el
@@ -0,0 +1,52 @@
+;;;; compile-all.el,v 1.2 1992/04/07 20:49:10 berliner Exp
+;;;; This file byte-compiles all .el files in pcl-cvs release 1.02.
+;;;;
+;;;; Copyright (C) 1991 Inge Wallin
+;;;;
+;;;; This file is part of the GNU Emacs lisp library, Elib.
+;;;;
+;;;; 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 elib-files '("elib-node"
+ "elib-dll"
+ "cookie"
+ "pcl-cvs"))
+
+
+(defun compile-file-if-necessary (file)
+ "Compile the Elib file 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 elib.
+Be sure to have . in load-path since a number of files in elib
+depend on other files and we always want the newer one even if
+a previous version of elib exists."
+
+ (interactive)
+ (setq load-path (append '(".") load-path))
+ (mapcar (function compile-file-if-necessary)
+ elib-files))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el
new file mode 100644
index 0000000..8bd4bdf
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/cookie.el
@@ -0,0 +1,884 @@
+;;; cookie.el,v 1.2 1992/04/07 20:49:12 berliner Exp
+;;; cookie.el -- Utility to display cookies in buffers
+;;; Copyright (C) 1991, 1992 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.
+
+;;;; TO-DO: Byt namn! tin -> wrapper (eller n}got b{ttre).
+
+;;; Note that this file is still under development. Comments,
+;;; enhancements and bug fixes are welcome.
+;;; Send them to ceder@lysator.liu.se.
+
+(defun impl nil (error "Not yet implemented!"))
+
+;;; Cookie is a package that imlements a connection between an
+;;; elib-dll and the contents of a buffer. Possible uses are dired
+;;; (have all files in a list, and show them), buffer-list,
+;;; kom-prioritize (in the LysKOM elisp client) and others. pcl-cvs.el
+;;; uses cookie.el.
+;;;
+;;; A cookie buffer contains a header, any number of cookies, and a
+;;; footer. The header and footer are constant strings that are given
+;;; to cookie-create when the buffer is placed under cookie. Each cookie
+;;; is displayed in the buffer by calling a user-supplied function
+;;; that takes a cookie and returns a string. The string may be
+;;; empty, or contain any number of lines. An extra newline is always
+;;; appended unless the string is empty.
+;;;
+;;; Cookie does not affect the mode of the buffer in any way. It
+;;; merely makes it easy to connect an underlying data representation
+;;; to the buffer contents.
+;;;
+;;; The cookie-node data type:
+;;; start-marker
+;;; ;; end-marker This field is no longer present.
+;;; cookie The user-supplied element.
+;;;
+;;; A dll of cookie-nodes are held in the buffer local variable
+;;; cake-tin.
+;;;
+;;; A tin is an object that contains one cookie. You can get the next
+;;; and previous tin.
+;;;
+
+(require 'elib-dll)
+(provide 'cookie)
+
+(defvar cookies nil
+ "A doubly linked list that contains the underlying data representation
+for the contents of a cookie buffer. The package elib-dll is used to
+manipulate this list.")
+
+(defvar cookie-pretty-printer nil
+ "The function that is used to pretty-print a cookie in this buffer.")
+
+(defvar cookie-header nil
+ "The tin that holds the header cookie.")
+
+(defvar cookie-footer nil
+ "The tin that holds the footer cookie.")
+
+(defvar cookie-last-tin nil
+ "The tin the cursor was positioned at, the last time the cookie
+package checked the cursor position. Buffer local in all buffers
+the cookie package works on. You may set this if your package
+thinks it knows where the cursor will be the next time this
+package is called. It can speed things up.
+
+It must never be set to a tin that has been deleted.")
+
+;;; ================================================================
+;;; Internal functions for use in the cookie package
+
+(put 'cookie-set-buffer 'lisp-indent-hook 1)
+
+(defmacro cookie-set-buffer (buffer &rest forms)
+
+ ;; Execute FORMS with BUFFER selected as current buffer.
+ ;; Return value of last form in FORMS. INTERNAL USE ONLY.
+
+ (let ((old-buffer (make-symbol "old-buffer")))
+ (` (let (((, old-buffer) (current-buffer)))
+ (set-buffer (get-buffer-create (, buffer)))
+ (unwind-protect
+ (progn (,@ forms))
+ (set-buffer (, old-buffer)))))))
+
+
+(defmacro cookie-filter-hf (tin)
+
+ ;; Evaluate TIN once and return it. BUT if it is
+ ;; equal to cookie-header or cookie-footer return nil instead.
+ ;; INTERNAL USE ONLY.
+
+ (let ((tempvar (make-symbol "tin")))
+ (` (let (((, tempvar) (, tin)))
+ (if (or (eq (, tempvar) cookie-header)
+ (eq (, tempvar) cookie-footer))
+ nil
+ (, tempvar))))))
+
+
+;;; cookie-tin
+;;; Constructor:
+
+(defun cookie-create-tin (start-marker
+ cookie)
+ ;; Create a tin. INTERNAL USE ONLY.
+ (cons 'COOKIE-TIN (vector start-marker nil cookie)))
+
+
+;;; Selectors:
+
+(defun cookie-tin-start-marker (cookie-tin)
+ ;; Get start-marker from cookie-tin. INTERNAL USE ONLY.
+ (elt (cdr cookie-tin) 0))
+
+;(defun cookie-tin-end-marker (cookie-tin)
+; ;;Get end-marker from cookie-tin. INTERNAL USE ONLY.
+; (elt (cdr cookie-tin) 1))
+
+(defun cookie-tin-cookie-safe (cookie-tin)
+ ;; Get cookie from cookie-tin. INTERNAL USE ONLY.
+ ;; Returns nil if given nil as input.
+ ;; This is the same as cookie-tin-cookie in version 18.57
+ ;; of emacs, but elt should signal an error when given nil
+ ;; as input (according to the info files).
+ (elt (cdr cookie-tin) 2))
+
+(defun cookie-tin-cookie (cookie-tin)
+ ;; Get cookie from cookie-tin. INTERNAL USE ONLY.
+ (elt (cdr cookie-tin) 2))
+
+
+;;; Modifiers:
+
+(defun set-cookie-tin-start-marker (cookie-tin newval)
+ ;; Set start-marker in cookie-tin to NEWVAL. INTERNAL USE ONLY.
+ (aset (cdr cookie-tin) 0 newval))
+
+;(defun set-cookie-tin-end-marker (cookie-tin newval)
+; ;; Set end-marker in cookie-tin to NEWVAL. INTERNAL USE ONLY.
+; (aset (cdr cookie-tin) 1 newval))
+
+(defun set-cookie-tin-cookie (cookie-tin newval)
+ ;; Set cookie in cookie-tin to NEWVAL. INTERNAL USE ONLY.
+ (aset (cdr cookie-tin) 2 newval))
+
+
+
+;;; Predicate:
+
+(defun cookie-tin-p (object)
+ ;; Return t if OBJECT is a tin. INTERNAL USE ONLY.
+ (eq (car-safe object) 'COOKIE-TIN))
+
+;;; end of cookie-tin data type.
+
+
+(defun cookie-create-tin-and-insert (cookie string pos)
+ ;; Insert STRING at POS in current buffer. Remember start
+ ;; position. Create a tin containing them and the COOKIE.
+ ;; INTERNAL USE ONLY.
+
+ (save-excursion
+ (goto-char pos)
+ ;; Remember the position as a number so that it doesn't move
+ ;; when we insert the string.
+ (let ((start (if (markerp pos)
+ (marker-position pos)
+ pos)))
+ ;; Use insert-before-markers so that the marker for the
+ ;; next cookie is updated.
+ (insert-before-markers string)
+ (insert-before-markers ?\n)
+ (cookie-create-tin (copy-marker start) cookie))))
+
+
+(defun cookie-delete-tin-internal (tin)
+ ;; Delete a cookie from the buffer. INTERNAL USE ONLY.
+ ;; Can not be used on the footer.
+ (delete-region (cookie-tin-start-marker (dll-element cookies tin))
+ (cookie-tin-start-marker
+ (dll-element cookies
+ (dll-next cookies tin)))))
+
+
+
+(defun cookie-refresh-tin (tin)
+ ;; Redisplay the cookie represented by TIN. INTERNAL USE ONLY.
+ ;; Can not be used on the footer.
+
+ (save-excursion
+ ;; First, remove the string:
+ (delete-region (cookie-tin-start-marker (dll-element cookies tin))
+ (1- (marker-position
+ (cookie-tin-start-marker
+ (dll-element cookies
+ (dll-next cookies tin))))))
+
+ ;; Calculate and insert the string.
+
+ (goto-char (cookie-tin-start-marker (dll-element cookies tin)))
+ (insert
+ (funcall cookie-pretty-printer
+ (cookie-tin-cookie (dll-element cookies tin))))))
+
+
+;;; ================================================================
+;;; The public members of the cookie package
+
+
+(defun cookie-cookie (buffer tin)
+ "Get the cookie from a TIN. Args: BUFFER TIN."
+ (cookie-set-buffer buffer
+ (cookie-tin-cookie (dll-element cookies tin))))
+
+
+
+
+(defun cookie-create (buffer pretty-printer &optional header footer)
+
+ "Start to use the cookie package in BUFFER.
+BUFFER may be a buffer or a buffer name. It is created if it does not exist.
+Beware that the entire contents of the buffer will be erased.
+PRETTY-PRINTER is a function that takes one cookie and returns a string
+to be displayed in the buffer. The string may be empty. If it is not
+empty a newline will be added automatically. It may span several lines.
+Optional third argument HEADER is a string that will always be present
+at the top of the buffer. HEADER should end with a newline. Optionaly
+fourth argument FOOTER is similar, and will always be inserted at the
+bottom of the buffer."
+
+ (cookie-set-buffer buffer
+
+ (erase-buffer)
+
+ (make-local-variable 'cookie-last-tin)
+ (make-local-variable 'cookie-pretty-printer)
+ (make-local-variable 'cookie-header)
+ (make-local-variable 'cookie-footer)
+ (make-local-variable 'cookies)
+
+ (setq cookie-last-tin nil)
+ (setq cookie-pretty-printer pretty-printer)
+ (setq cookies (dll-create))
+
+ (dll-enter-first cookies
+ (cookie-create-tin-and-insert
+ header header 0))
+ (setq cookie-header (dll-nth cookies 0))
+
+ (dll-enter-last cookies
+ (cookie-create-tin-and-insert
+ footer footer (point-max)))
+ (setq cookie-footer (dll-nth cookies -1))
+
+ (goto-char (point-min))
+ (forward-line 1)))
+
+
+(defun cookie-set-header (buffer header)
+ "Change the header. Args: BUFFER HEADER."
+ (impl))
+
+
+(defun cookie-set-footer (buffer header)
+ "Change the footer. Args: BUFFER FOOTER."
+ (impl))
+
+
+
+(defun cookie-enter-first (buffer cookie)
+ "Enter a COOKIE first in BUFFER.
+Args: BUFFER COOKIE."
+
+ (cookie-set-buffer buffer
+
+ ;; It is always safe to insert an element after the first element,
+ ;; because the header is always present. (dll-nth cookies 0) should
+ ;; never return nil.
+
+ (dll-enter-after
+ cookies
+ (dll-nth cookies 0)
+ (cookie-create-tin-and-insert
+ cookie
+ (funcall cookie-pretty-printer cookie)
+ (cookie-tin-start-marker
+ (dll-element cookies (dll-nth cookies 1)))))))
+
+
+
+(defun cookie-enter-last (buffer cookie)
+ "Enter a COOKIE last in BUFFER.
+Args: BUFFER COOKIE."
+
+ (cookie-set-buffer buffer
+
+ ;; Remember that the header and footer are always present. There
+ ;; is no need to check if (dll-nth cookies -2) returns nil.
+
+ (dll-enter-before
+ cookies
+ (dll-nth cookies -1)
+ (cookie-create-tin-and-insert
+ cookie
+ (funcall cookie-pretty-printer cookie)
+ (cookie-tin-start-marker (dll-last cookies))))))
+
+
+(defun cookie-enter-after (buffer node cookie)
+ (impl))
+
+
+(defun cookie-enter-before (buffer node cookie)
+ (impl))
+
+
+
+(defun cookie-next (buffer tin)
+ "Get the next tin. Args: BUFFER TIN.
+Returns nil if TIN is nil or the last cookie."
+ (if tin
+ (cookie-set-buffer buffer
+ (cookie-filter-hf (dll-next cookies tin)))))
+
+
+
+(defun cookie-previous (buffer tin)
+ "Get the previous tin. Args: BUFFER TIN.
+Returns nil if TIN is nil or the first cookie."
+ (if tin
+ (cookie-set-buffer buffer
+ (cookie-filter-hf (dll-previous cookies tin)))))
+
+
+(defun cookie-nth (buffer n)
+
+ "Return the Nth tin. Args: BUFFER N.
+N counts from zero. Nil is returned if there is less than N cookies.
+If N is negative, return the -(N+1)th last element.
+Thus, (cookie-nth dll 0) returns the first node,
+and (cookie-nth dll -1) returns the last node.
+
+Use cookie-cookie to extract the cookie from the tin."
+
+ (cookie-set-buffer buffer
+
+ ;; Skip the header (or footer, if n is negative).
+ (if (< n 0)
+ (setq n (1- n))
+ (setq n (1+ n)))
+
+ (cookie-filter-hf (dll-nth cookies n))))
+
+
+
+(defun cookie-delete (buffer tin)
+ "Delete a cookie. Args: BUFFER TIN."
+
+ (cookie-set-buffer buffer
+ (if (eq cookie-last-tin tin)
+ (setq cookie-last-tin nil))
+
+ (cookie-delete-tin-internal tin)
+ (dll-delete cookies tin)))
+
+
+
+(defun cookie-delete-first (buffer)
+ "Delete first cookie and return it. Args: BUFFER.
+Returns nil if there is no cookie left."
+
+ (cookie-set-buffer buffer
+
+ ;; We have to check that we do not try to delete the footer.
+
+ (let ((tin (dll-nth cookies 1))) ;Skip the header.
+ (if (eq tin cookie-footer)
+ nil
+ (cookie-delete-tin-internal tin)
+ (cookie-tin-cookie (dll-delete cookies tin))))))
+
+
+
+(defun cookie-delete-last (buffer)
+ "Delete last cookie and return it. Args: BUFFER.
+Returns nil if there is no cookie left."
+
+ (cookie-set-buffer buffer
+
+ ;; We have to check that we do not try to delete the header.
+
+ (let ((tin (dll-nth cookies -2))) ;Skip the footer.
+ (if (eq tin cookie-header)
+ nil
+ (cookie-delete-tin-internal tin)
+ (cookie-tin-cookie (dll-delete cookies tin))))))
+
+
+
+(defun cookie-first (buffer)
+
+ "Return the first cookie in BUFFER. The cookie is not removed."
+
+ (cookie-set-buffer buffer
+ (let ((tin (cookie-filter-hf (dll-nth cookies -1))))
+ (if tin
+ (cookie-tin-cookie-safe
+ (dll-element cookies tin))))))
+
+
+(defun cookie-last (buffer)
+
+ "Return the last cookie in BUFFER. The cookie is not removed."
+
+ (cookie-set-buffer buffer
+ (let ((tin (cookie-filter-hf (dll-nth cookies -2))))
+ (if tin
+ (cookie-tin-cookie-safe
+ (dll-element cookies tin))))))
+
+
+(defun cookie-empty (buffer)
+
+ "Return true if there are no cookies in BUFFER."
+
+ (cookie-set-buffer buffer
+ (eq (dll-nth cookies 1) cookie-footer)))
+
+
+(defun cookie-length (buffer)
+
+ "Return number of cookies in BUFFER."
+
+ ;; Don't count the footer and header.
+
+ (cookie-set-buffer buffer
+ (- (dll-length cookies) 2)))
+
+
+(defun cookie-all (buffer)
+
+ "Return a list of all cookies in BUFFER."
+
+ (cookie-set-buffer buffer
+ (let (result
+ (tin (dll-nth cookies -2)))
+ (while (not (eq tin cookie-header))
+ (setq result (cons (cookie-tin-cookie (dll-element cookies tin))
+ result))
+ (setq tin (dll-previous cookies tin)))
+ result)))
+
+(defun cookie-clear (buffer)
+
+ "Remove all cookies in buffer."
+
+ (cookie-set-buffer buffer
+ (cookie-create buffer cookie-pretty-printer
+ (cookie-tin-cookie (dll-element cookies cookie-header))
+ (cookie-tin-cookie (dll-element cookies cookie-footer)))))
+
+
+
+(defun cookie-map (map-function buffer &rest map-args)
+
+ "Apply MAP-FUNCTION to all cookies in BUFFER.
+MAP-FUNCTION is applied to the first element first.
+If MAP-FUNCTION returns non-nil the cookie will be refreshed.
+
+Note that BUFFER will be current buffer when MAP-FUNCTION is called.
+
+If more than two arguments are given to cookie-map, remaining
+arguments will be passed to MAP-FUNCTION."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies 1))
+ result)
+
+ (while (not (eq tin cookie-footer))
+
+ (if (apply map-function
+ (cookie-tin-cookie (dll-element cookies tin))
+ map-args)
+ (cookie-refresh-tin tin))
+
+ (setq tin (dll-next cookies tin))))))
+
+
+
+(defun cookie-map-reverse (map-function buffer &rest map-args)
+
+ "Apply MAP-FUNCTION to all cookies in BUFFER.
+MAP-FUNCTION is applied to the last cookie first.
+If MAP-FUNCTION returns non-nil the cookie will be refreshed.
+
+Note that BUFFER will be current buffer when MAP-FUNCTION is called.
+
+If more than two arguments are given to cookie-map, remaining
+arguments will be passed to MAP-FUNCTION."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies -2))
+ result)
+
+ (while (not (eq tin cookie-header))
+
+ (if (apply map-function
+ (cookie-tin-cookie (dll-element cookies tin))
+ map-args)
+ (cookie-refresh-tin tin))
+
+ (setq tin (dll-previous cookies tin))))))
+
+
+
+(defun cookie-enter-cookies (buffer cookie-list)
+
+ "Insert all cookies in the list COOKIE-LIST last in BUFFER.
+Args: BUFFER COOKIE-LIST."
+
+ (while cookie-list
+ (cookie-enter-last buffer (car cookie-list))
+ (setq cookie-list (cdr cookie-list))))
+
+
+(defun cookie-filter (buffer predicate)
+
+ "Remove all cookies in BUFFER for which PREDICATE returns nil.
+Note that BUFFER will be current-buffer when PREDICATE is called.
+
+The PREDICATE is called with one argument, the cookie."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies 1))
+ next)
+ (while (not (eq tin cookie-footer))
+ (setq next (dll-next cookies tin))
+ (if (funcall predicate (cookie-tin-cookie (dll-element cookies tin)))
+ nil
+ (cookie-delete-tin-internal tin)
+ (dll-delete cookies tin))
+ (setq tin next)))))
+
+
+(defun cookie-filter-tins (buffer predicate)
+
+ "Remove all cookies in BUFFER for which PREDICATE returns nil.
+Note that BUFFER will be current-buffer when PREDICATE is called.
+
+The PREDICATE is called with one argument, the tin."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies 1))
+ next)
+ (while (not (eq tin cookie-footer))
+ (setq next (dll-next cookies tin))
+ (if (funcall predicate tin)
+ nil
+ (cookie-delete-tin-internal tin)
+ (dll-delete cookies tin))
+ (setq tin next)))))
+
+(defun cookie-pos-before-middle-p (pos tin1 tin2)
+
+ "Return true if POS is in the first half of the region defined by TIN1 and
+TIN2."
+
+ (< pos (/ (+ (cookie-tin-start-marker (dll-element cookeis tin1))
+ (cookie-tin-start-marker (dll-element cookeis tin2)))
+ 2)))
+
+
+(defun cookie-get-selection (buffer pos &optional guess force-guess)
+
+ "Return the tin the POS is within.
+Args: BUFFER POS &optional GUESS FORCE-GUESS.
+GUESS should be a tin that it is likely that POS is near. If FORCE-GUESS
+is non-nil GUESS is always used as a first guess, otherwise the first
+guess is the first tin, last tin, or GUESS, whichever is nearest to
+pos in the BUFFER.
+
+If pos points within the header, the first cookie is returned.
+If pos points within the footer, the last cookie is returned.
+Nil is returned if there is no cookie.
+
+It is often good to specify cookie-last-tin as GUESS, but remember
+that cookie-last-tin is buffer local in all buffers that cookie
+operates on."
+
+ (cookie-set-buffer buffer
+
+ (cond
+ ; No cookies present?
+ ((eq (dll-nth cookies 1) (dll-nth cookies -1))
+ nil)
+
+ ; Before first cookie?
+ ((< pos (cookie-tin-start-marker
+ (dll-element cookies (dll-nth cookies 1))))
+ (dll-nth cookies 1))
+
+ ; After last cookie?
+ ((>= pos (cookie-tin-start-marker (dll-last cookies)))
+ (dll-nth cookies -2))
+
+ ; We now now that pos is within a cookie.
+ (t
+ ; Make an educated guess about which of the three known
+ ; cookies (the first, the last, or GUESS) is nearest.
+ (setq
+ guess
+ (cond
+ (force-guess guess)
+ (guess
+ (cond
+ ;; Closest to first cookie?
+ ((cookie-pos-before-middle-p
+ pos guess
+ (dll-nth cookies 1))
+ (dll-nth cookies 1))
+ ;; Closest to GUESS?
+ ((cookie-pos-before-middle-p
+ pos guess
+ cookie-footer)
+ guess)
+ ;; Closest to last cookie.
+ (t (dll-previous cookies cookie-footer))))
+ (t
+ ;; No guess given.
+ (cond
+ ;; First half?
+ ((cookie-pos-before-middle-p
+ pos (dll-nth cookies 1)
+ cookie-footer)
+ (dll-nth cookies 1))
+ (t (dll-previous cookies cookie-footer))))))
+
+ ;; GUESS is now a "best guess".
+
+ ;; Find the correct cookie. First determine in which direction
+ ;; it lies, and then move in that direction until it is found.
+
+ (cond
+ ;; Is pos after the guess?
+ ((>= pos (cookie-tin-start-marker (dll-element cookiess guess)))
+
+ ;; Loop until we are exactly one cookie too far down...
+ (while (>= pos (cookie-tin-start-marker (dll-element cookiess guess)))
+ (setq guess (dll-next cookies guess)))
+
+ ;; ...and return the previous cookie.
+ (dll-previous cookies guess))
+
+ ;; Pos is before guess
+ (t
+
+ (while (< pos (cookie-tin-start-marker (dll-element cookiess guess)))
+ (setq guess (dll-previous cookies guess)))
+
+ guess))))))
+
+
+(defun cookie-start-marker (buffer tin)
+
+ "Return start-position of a cookie in BUFFER.
+Args: BUFFER TIN.
+The marker that is returned should not be modified in any way,
+and is only valid until the contents of the cookie buffer changes."
+
+ (cookie-set-buffer buffer
+ (cookie-tin-start-marker (dll-element cookies tin))))
+
+
+(defun cookie-end-marker (buffer tin)
+
+ "Return end-position of a cookie in BUFFER.
+Args: BUFFER TIN.
+The marker that is returned should not be modified in any way,
+and is only valid until the contents of the cookie buffer changes."
+
+ (cookie-set-buffer buffer
+ (cookie-tin-start-marker
+ (dll-element cookies (dll-next cookies tin)))))
+
+
+
+(defun cookie-refresh (buffer)
+
+ "Refresh all cookies in BUFFER.
+Cookie-pretty-printer will be called for all cookies and the new result
+displayed.
+
+See also cookie-invalidate-tins."
+
+ (cookie-set-buffer buffer
+
+ (erase-buffer)
+
+ (set-marker (cookie-tin-start-marker (dll-element cookies cookie-header))
+ (point) buffer)
+ (insert (cookie-tin-cookie (dll-element cookies cookie-header)))
+ (insert "\n")
+
+ (let ((tin (dll-nth cookies 1)))
+ (while (not (eq tin cookie-footer))
+
+ (set-marker (cookie-tin-start-marker (dll-element cookies tin))
+ (point) buffer)
+ (insert
+ (funcall cookie-pretty-printer
+ (cookie-tin-cookie (dll-element cookies tin))))
+ (insert "\n")
+ (setq tin (dll-next cookies tin))))
+
+ (set-marker (cookie-tin-start-marker (dll-element cookies cookie-footer))
+ (point) buffer)
+ (insert (cookie-tin-cookie (dll-element cookies cookie-footer)))
+ (insert "\n")))
+
+
+(defun cookie-invalidate-tins (buffer &rest tins)
+
+ "Refresh some cookies.
+Args: BUFFER &rest TINS."
+
+ (cookie-set-buffer buffer
+
+ (while tins
+ (cookie-refresh-tin (car tins))
+ (setq tins (cdr tins)))))
+
+
+;;; Cookie movement commands.
+
+(defun cookie-set-goal-column (buffer goal)
+ "Set goal-column for BUFFER.
+Args: BUFFER GOAL.
+goal-column is made buffer-local."
+ (cookie-set-buffer buffer
+ (make-local-variable 'goal-column)
+ (setq goal-column goal)))
+
+
+(defun cookie-previous-cookie (buffer pos arg)
+ "Move point to the ARGth previous cookie.
+Don't move if we are at the first cookie.
+ARG is the prefix argument when called interactively.
+Args: BUFFER POS ARG.
+Sets cookie-last-tin to the cookie we move to."
+
+ (interactive (list (current-buffer) (point)
+ (prefix-numeric-value current-prefix-arg)))
+
+ (cookie-set-buffer buffer
+ (setq cookie-last-tin
+ (cookie-get-selection buffer pos cookie-last-tin))
+
+ (while (and cookie-last-tin (> arg 0))
+ (setq arg (1- arg))
+ (setq cookie-last-tin
+ (dll-previous cookies cookie-last-tin)))
+
+ ;; Never step above the first cookie.
+
+ (if (null (cookie-filter-hf cookie-last-tin))
+ (setq cookie-last-tin (dll-nth cookies 1)))
+
+ (goto-char
+ (cookie-tin-start-marker
+ (dll-element cookies cookie-last-tin)))
+
+ (if goal-column
+ (move-to-column goal-column))))
+
+
+
+(defun cookie-next-cookie (buffer pos arg)
+ "Move point to the ARGth next cookie.
+Don't move if we are at the last cookie.
+ARG is the prefix argument when called interactively.
+Args: BUFFER POS ARG.
+Sets cookie-last-tin to the cookie we move to."
+
+ (interactive (list (current-buffer) (point)
+ (prefix-numeric-value current-prefix-arg)))
+
+ (cookie-set-buffer buffer
+ (setq cookie-last-tin
+ (cookie-get-selection buffer pos cookie-last-tin))
+
+ (while (and cookie-last-tin (> arg 0))
+ (setq arg (1- arg))
+ (setq cookie-last-tin
+ (dll-next cookies cookie-last-tin)))
+
+ (if (null (cookie-filter-hf cookie-last-tin))
+ (setq cookie-last-tin (dll-nth cookies -2)))
+
+ (goto-char
+ (cookie-tin-start-marker
+ (dll-element cookies cookie-last-tin)))
+
+ (if goal-column
+ (move-to-column goal-column))))
+
+
+(defun cookie-collect-tins (buffer predicate &rest predicate-args)
+
+ "Return a list of all tins in BUFFER whose cookie PREDICATE
+returns true for.
+PREDICATE is a function that takes a cookie as its argument.
+The tins on the returned list will appear in the same order
+as in the buffer. You should not rely on in which order PREDICATE
+is called. Note that BUFFER is current-buffer when PREDICATE
+is called. (If you call cookie-collect with another buffer set
+as current-buffer and need to access buffer-local variables
+from that buffer within PREDICATE you must send them via
+PREDICATE-ARGS).
+
+If more than two arguments are given to cookie-collect the remaining
+arguments will be passed to PREDICATE.
+
+Use cookie-cookie to get the cookie from the tin."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies -2))
+ result)
+
+ (while (not (eq tin cookie-header))
+
+ (if (apply predicate
+ (cookie-tin-cookie (dll-element cookies tin))
+ predicate-args)
+ (setq result (cons tin result)))
+
+ (setq tin (dll-previous cookies tin)))
+ result)))
+
+
+(defun cookie-collect-cookies (buffer predicate &rest predicate-args)
+
+ "Return a list of all cookies in BUFFER that PREDICATE
+returns true for.
+PREDICATE is a function that takes a cookie as its argument.
+The cookie on the returned list will appear in the same order
+as in the buffer. You should not rely on in which order PREDICATE
+is called. Note that BUFFER is current-buffer when PREDICATE
+is called. (If you call cookie-collect with another buffer set
+as current-buffer and need to access buffer-local variables
+from that buffer within PREDICATE you must send them via
+PREDICATE-ARGS).
+
+If more than two arguments are given to cookie-collect the remaining
+arguments will be passed to PREDICATE."
+
+ (cookie-set-buffer buffer
+ (let ((tin (dll-nth cookies -2))
+ result)
+
+ (while (not (eq tin cookie-header))
+
+ (if (apply predicate
+ (cookie-tin-cookie (dll-element cookies tin))
+ predicate-args)
+ (setq result (cons (cookie-tin-cookie (dll-element cookies tin))
+ result)))
+
+ (setq tin (dll-previous cookies tin)))
+ result)))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el
new file mode 100644
index 0000000..733ff86
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll-debug.el
@@ -0,0 +1,298 @@
+;;; elib-dll-debug -- A slow implementation of elib-dll for debugging.
+;;; elib-dll-debug.el,v 1.2 1992/04/07 20:49:13 berliner Exp
+;;; Copyright (C) 1991,1992 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.
+
+
+;;; This is a plug-in replacement for elib-dll.el. It is dreadfully
+;;; slow, but it facilitates debugging. Don't trust the comments in
+;;; this file too much.
+(provide 'elib-dll)
+
+;;;
+;;; A doubly linked list consists of one cons cell which holds the tag
+;;; 'DL-LIST in the car cell and the list in the cdr
+;;; cell. The doubly linked list is implemented as a normal list. You
+;;; should use elib-dll.el and not this package in debugged code. This
+;;; package is not written for speed...
+;;;
+
+;;; ================================================================
+;;; Internal functions for use in the doubly linked list package
+
+(defun dll-get-dummy-node (dll)
+
+ ;; Return the dummy node. INTERNAL USE ONLY.
+ dll)
+
+(defun dll-list-nodes (dll)
+
+ ;; Return a list of all nodes in DLL. INTERNAL USE ONLY.
+
+ (cdr dll))
+
+(defun dll-set-from-node-list (dll list)
+
+ ;; Set the contents of DLL to the nodes in LIST.
+ ;; INTERNAL USE ONLY.
+
+ (setcdr dll list))
+
+(defun dll-get-node-before (dll node)
+ ;; Return the node in DLL that points to NODE. Use
+ ;; (dll-get-node-before some-list nil) to get the last node.
+ ;; INTERNAL USE ONLY.
+ (while (and dll (not (eq (cdr dll) node)))
+ (setq dll (cdr dll)))
+ (if (not dll)
+ (error "Node not on list"))
+ dll)
+
+(defmacro dll-insert-after (node element)
+ (let ((node-v (make-symbol "node"))
+ (element-v (make-symbol "element")))
+ (` (let (((, node-v) (, node))
+ ((, element-v) (, element)))
+ (setcdr (, node-v) (cons (, element-v) (cdr (, node-v))))))))
+
+;;; ===================================================================
+;;; The public functions which operate on doubly linked lists.
+
+(defmacro dll-element (dll node)
+
+ "Get the element of a NODE in a doubly linked list DLL.
+Args: DLL NODE."
+
+ (` (car (, node))))
+
+
+(defun dll-create ()
+ "Create an empty doubly linked list."
+ (cons 'DL-LIST nil))
+
+
+(defun dll-p (object)
+ "Return t if OBJECT is a doubly linked list, otherwise return nil."
+ (eq (car-safe object) 'DL-LIST))
+
+
+(defun dll-enter-first (dll element)
+ "Add an element first on a doubly linked list.
+Args: DLL ELEMENT."
+ (setcdr dll (cons element (cdr dll))))
+
+
+(defun dll-enter-last (dll element)
+ "Add an element last on a doubly linked list.
+Args: DLL ELEMENT."
+ (dll-insert-after (dll-get-node-before dll nil) element))
+
+
+(defun dll-enter-after (dll node element)
+ "In the doubly linked list DLL, insert a node containing ELEMENT after NODE.
+Args: DLL NODE ELEMENT."
+
+ (dll-get-node-before dll node)
+ (dll-insert-after node element))
+
+
+(defun dll-enter-before (dll node element)
+ "In the doubly linked list DLL, insert a node containing ELEMENT before NODE.
+Args: DLL NODE ELEMENT."
+
+ (dll-insert-after (dll-get-node-before dll node) element))
+
+
+
+(defun dll-next (dll node)
+ "Return the node after NODE, or nil if NODE is the last node.
+Args: DLL NODE."
+
+ (dll-get-node-before dll node)
+ (cdr node))
+
+
+(defun dll-previous (dll node)
+ "Return the node before NODE, or nil if NODE is the first node.
+Args: DLL NODE."
+
+ (dll-get-node-before dll node))
+
+
+(defun dll-delete (dll node)
+
+ "Delete NODE from the doubly linked list DLL.
+Args: DLL NODE. Return the element of node."
+
+ ;; This is a no-op when applied to the dummy node. This will return
+ ;; nil if applied to the dummy node since it always contains nil.
+
+ (setcdr (dll-get-node-before dll node) (cdr node)))
+
+
+(defun dll-delete-first (dll)
+
+ "Delete the first NODE from the doubly linked list DLL.
+Return the element. Args: DLL. Returns nil if the DLL was empty."
+
+ ;; Relies on the fact that dll-delete does nothing and
+ ;; returns nil if given the dummy node.
+
+ (setcdr dll (cdr (cdr dll))))
+
+
+(defun dll-delete-last (dll)
+
+ "Delete the last NODE from the doubly linked list DLL.
+Return the element. Args: DLL. Returns nil if the DLL was empty."
+
+ ;; Relies on the fact that dll-delete does nothing and
+ ;; returns nil if given the dummy node.
+
+ (setcdr dll (dll-get-node-before dll nil) nil))
+
+
+(defun dll-first (dll)
+
+ "Return the first element on the doubly linked list DLL.
+Return nil if the list is empty. The element is not removed."
+
+ (car (cdr dll)))
+
+
+
+
+(defun dll-last (dll)
+
+ "Return the last element on the doubly linked list DLL.
+Return nil if the list is empty. The element is not removed."
+
+ (car (dll-get-node-before dll nil)))
+
+
+
+(defun dll-nth (dll n)
+
+ "Return the Nth node from the doubly linked list DLL.
+ Args: DLL N
+N counts from zero. If DLL is not that long, nil is returned.
+If N is negative, return the -(N+1)th last element.
+Thus, (dll-nth dll 0) returns the first node,
+and (dll-nth dll -1) returns the last node."
+
+ ;; Branch 0 ("follow left pointer") is used when n is negative.
+ ;; Branch 1 ("follow right pointer") is used otherwise.
+
+ (if (>= n 0)
+ (nthcdr n (cdr dll))
+ (unwind-protect
+ (progn (setcdr dll (nreverse (cdr dll)))
+ (nthcdr (- n) dll))
+ (setcdr dll (nreverse (cdr dll))))))
+
+(defun dll-empty (dll)
+
+ "Return t if the doubly linked list DLL is empty, nil otherwise"
+
+ (not (cdr dll)))
+
+(defun dll-length (dll)
+
+ "Returns the number of elements in the doubly linked list DLL."
+
+ (length (cdr dll)))
+
+
+
+(defun dll-copy (dll &optional element-copy-fnc)
+
+ "Return a copy of the doubly linked list DLL.
+If optional second argument ELEMENT-COPY-FNC is non-nil it should be
+a function that takes one argument, an element, and returns a copy of it.
+If ELEMENT-COPY-FNC is not given the elements are not copied."
+
+ (if element-copy-fnc
+ (cons 'DL-LIST (mapcar element-copy-fnc (cdr dll)))
+ (copy-sequence dll)))
+
+
+(defun dll-all (dll)
+
+ "Return all elements on the double linked list DLL as an ordinary list."
+
+ (cdr dll))
+
+
+(defun dll-clear (dll)
+
+ "Clear the doubly linked list DLL, i.e. make it completely empty."
+
+ (setcdr dll nil))
+
+
+(defun dll-map (map-function dll)
+
+ "Apply MAP-FUNCTION to all elements in the doubly linked list DLL.
+The function is applied to the first element first."
+
+ (mapcar map-function (cdr dll)))
+
+
+(defun dll-map-reverse (map-function dll)
+
+ "Apply MAP-FUNCTION to all elements in the doubly linked list DLL.
+The function is applied to the last element first."
+
+ (unwind-protect
+ (setcdr dll (nreverse (cdr dll)))
+ (mapcar map-function (cdr dll))
+ (setcdr dll (nreverse (cdr dll)))))
+
+
+(defun dll-create-from-list (list)
+
+ "Given an elisp LIST create a doubly linked list with the same elements."
+
+ (cons 'DL-LIST list))
+
+
+
+(defun dll-sort (dll predicate)
+
+ "Sort the doubly linked list DLL, stably, comparing elements using PREDICATE.
+Returns the sorted list. DLL is modified by side effects.
+PREDICATE is called with two elements of DLL, and should return T
+if the first element is \"less\" than the second."
+
+ (setcdr dll (sort (cdr dll) predicate))
+ dll)
+
+
+(defun dll-filter (dll predicate)
+
+ "Remove all elements in the doubly linked list DLL for which PREDICATE
+return nil."
+
+ (let* ((prev dll)
+ (node (cdr dll)))
+
+ (while node
+ (cond
+ ((funcall predicate (car node))
+ (setq prev node))
+ (t
+ (setcdr prev (cdr node))))
+ (setq node (cdr node)))))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el
new file mode 100644
index 0000000..855bd19
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-dll.el
@@ -0,0 +1,386 @@
+;;; elib-dll.el,v 1.2 1992/04/07 20:49:15 berliner Exp
+;;; elib-dll.el -- Some primitives for Doubly linked lists.
+;;; Copyright (C) 1991, 1992 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.
+
+;;; Mail bug reports to ceder@lysator.liu.se.
+
+(require 'elib-node)
+(provide 'elib-dll)
+
+;;;
+;;; A doubly linked list consists of one cons cell which holds the tag
+;;; 'DL-LIST in the car cell and a pointer to a dummy node in the cdr
+;;; cell. The doubly linked list is implemented as a circular list
+;;; with the dummy node first and last. The dummy node is recognized
+;;; by comparing it to the node which the cdr of the cons cell points
+;;; to.
+;;;
+
+;;; ================================================================
+;;; Internal functions for use in the doubly linked list package
+
+(defun dll-get-dummy-node (dll)
+
+ ;; Return the dummy node. INTERNAL USE ONLY.
+ (cdr dll))
+
+(defun dll-list-nodes (dll)
+
+ ;; Return a list of all nodes in DLL. INTERNAL USE ONLY.
+
+ (let* ((result nil)
+ (dummy (dll-get-dummy-node dll))
+ (node (elib-node-left dummy)))
+
+ (while (not (eq node dummy))
+ (setq result (cons node result))
+ (setq node (elib-node-left node)))
+
+ result))
+
+(defun dll-set-from-node-list (dll list)
+
+ ;; Set the contents of DLL to the nodes in LIST.
+ ;; INTERNAL USE ONLY.
+
+ (dll-clear dll)
+ (let* ((dummy (dll-get-dummy-node dll))
+ (left dummy))
+ (while list
+ (elib-node-set-left (car list) left)
+ (elib-node-set-right left (car list))
+ (setq left (car list))
+ (setq list (cdr list)))
+
+ (elib-node-set-right left dummy)
+ (elib-node-set-left dummy left)))
+
+
+;;; ===================================================================
+;;; The public functions which operate on doubly linked lists.
+
+(defmacro dll-element (dll node)
+
+ "Get the element of a NODE in a doubly linked list DLL.
+Args: DLL NODE."
+
+ (` (elib-node-data (, node))))
+
+
+(defun dll-create ()
+ "Create an empty doubly linked list."
+ (let ((dummy-node (elib-node-create nil nil nil)))
+ (elib-node-set-right dummy-node dummy-node)
+ (elib-node-set-left dummy-node dummy-node)
+ (cons 'DL-LIST dummy-node)))
+
+(defun dll-p (object)
+ "Return t if OBJECT is a doubly linked list, otherwise return nil."
+ (eq (car-safe object) 'DL-LIST))
+
+(defun dll-enter-first (dll element)
+ "Add an element first on a doubly linked list.
+Args: DLL ELEMENT."
+ (dll-enter-after
+ dll
+ (dll-get-dummy-node dll)
+ element))
+
+
+(defun dll-enter-last (dll element)
+ "Add an element last on a doubly linked list.
+Args: DLL ELEMENT."
+ (dll-enter-before
+ dll
+ (dll-get-dummy-node dll)
+ element))
+
+
+(defun dll-enter-after (dll node element)
+ "In the doubly linked list DLL, insert a node containing ELEMENT after NODE.
+Args: DLL NODE ELEMENT."
+
+ (let ((new-node (elib-node-create
+ node (elib-node-right node)
+ element)))
+ (elib-node-set-left (elib-node-right node) new-node)
+ (elib-node-set-right node new-node)))
+
+
+(defun dll-enter-before (dll node element)
+ "In the doubly linked list DLL, insert a node containing ELEMENT before NODE.
+Args: DLL NODE ELEMENT."
+
+ (let ((new-node (elib-node-create
+ (elib-node-left node) node
+ element)))
+ (elib-node-set-right (elib-node-left node) new-node)
+ (elib-node-set-left node new-node)))
+
+
+
+(defun dll-next (dll node)
+ "Return the node after NODE, or nil if NODE is the last node.
+Args: DLL NODE."
+
+ (if (eq (elib-node-right node) (dll-get-dummy-node dll))
+ nil
+ (elib-node-right node)))
+
+
+(defun dll-previous (dll node)
+ "Return the node before NODE, or nil if NODE is the first node.
+Args: DLL NODE."
+
+ (if (eq (elib-node-left node) (dll-get-dummy-node dll))
+ nil
+ (elib-node-left node)))
+
+
+(defun dll-delete (dll node)
+
+ "Delete NODE from the doubly linked list DLL.
+Args: DLL NODE. Return the element of node."
+
+ ;; This is a no-op when applied to the dummy node. This will return
+ ;; nil if applied to the dummy node since it always contains nil.
+
+ (elib-node-set-right (elib-node-left node) (elib-node-right node))
+ (elib-node-set-left (elib-node-right node) (elib-node-left node))
+ (dll-element dll node))
+
+
+
+(defun dll-delete-first (dll)
+
+ "Delete the first NODE from the doubly linked list DLL.
+Return the element. Args: DLL. Returns nil if the DLL was empty."
+
+ ;; Relies on the fact that dll-delete does nothing and
+ ;; returns nil if given the dummy node.
+
+ (dll-delete dll (elib-node-right (dll-get-dummy-node dll))))
+
+
+(defun dll-delete-last (dll)
+
+ "Delete the last NODE from the doubly linked list DLL.
+Return the element. Args: DLL. Returns nil if the DLL was empty."
+
+ ;; Relies on the fact that dll-delete does nothing and
+ ;; returns nil if given the dummy node.
+
+ (dll-delete dll (elib-node-left (dll-get-dummy-node dll))))
+
+
+(defun dll-first (dll)
+
+ "Return the first element on the doubly linked list DLL.
+Return nil if the list is empty. The element is not removed."
+
+ (if (eq (elib-node-right (dll-get-dummy-node dll))
+ (dll-get-dummy-node dll))
+ nil
+ (elib-node-data (elib-node-right (dll-get-dummy-node dll)))))
+
+
+
+
+(defun dll-last (dll)
+
+ "Return the last element on the doubly linked list DLL.
+Return nil if the list is empty. The element is not removed."
+
+ (if (eq (elib-node-left (dll-get-dummy-node dll))
+ (dll-get-dummy-node dll))
+ nil
+ (elib-node-data (elib-node-left (dll-get-dummy-node dll)))))
+
+
+
+(defun dll-nth (dll n)
+
+ "Return the Nth node from the doubly linked list DLL.
+ Args: DLL N
+N counts from zero. If DLL is not that long, nil is returned.
+If N is negative, return the -(N+1)th last element.
+Thus, (dll-nth dll 0) returns the first node,
+and (dll-nth dll -1) returns the last node."
+
+ ;; Branch 0 ("follow left pointer") is used when n is negative.
+ ;; Branch 1 ("follow right pointer") is used otherwise.
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (branch (if (< n 0) 0 1))
+ (node (elib-node-branch dummy branch)))
+
+ (if (< n 0)
+ (setq n (- -1 n)))
+
+ (while (and (not (eq dummy node))
+ (> n 0))
+ (setq node (elib-node-branch node branch))
+ (setq n (1- n)))
+
+ (if (eq dummy node)
+ nil
+ node)))
+
+
+(defun dll-empty (dll)
+
+ "Return t if the doubly linked list DLL is empty, nil otherwise"
+
+ (eq (elib-node-left (dll-get-dummy-node dll))
+ (dll-get-dummy-node dll)))
+
+(defun dll-length (dll)
+
+ "Returns the number of elements in the doubly linked list DLL."
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (node (elib-node-right dummy))
+ (n 0))
+
+ (while (not (eq node dummy))
+ (setq node (elib-node-right node))
+ (setq n (1+ n)))
+
+ n))
+
+
+
+(defun dll-copy (dll &optional element-copy-fnc)
+
+ "Return a copy of the doubly linked list DLL.
+If optional second argument ELEMENT-COPY-FNC is non-nil it should be
+a function that takes one argument, an element, and returns a copy of it.
+If ELEMENT-COPY-FNC is not given the elements are not copied."
+
+ (let ((result (dll-create))
+ (node (dll-nth dll 0)))
+ (if element-copy-fnc
+
+ ;; Copy the elements with the user-supplied function.
+ (while node
+ (dll-enter-last result
+ (funcall element-copy-fnc
+ (dll-element dll node)))
+ (setq node (dll-next dll node)))
+
+ ;; Don't try to copy the elements - they might be
+ ;; circular lists, or anything at all...
+ (while node
+ (dll-enter-last result (dll-element dll node))
+ (setq node (dll-next dll node))))
+
+ result))
+
+
+
+(defun dll-all (dll)
+
+ "Return all elements on the double linked list DLL as an ordinary list."
+
+ (let* ((result nil)
+ (dummy (dll-get-dummy-node dll))
+ (node (elib-node-left dummy)))
+
+ (while (not (eq node dummy))
+ (setq result (cons (dll-element dll node) result))
+ (setq node (elib-node-left node)))
+
+ result))
+
+
+(defun dll-clear (dll)
+
+ "Clear the doubly linked list DLL, i.e. make it completely empty."
+
+ (elib-node-set-left (dll-get-dummy-node dll) (dll-get-dummy-node dll))
+ (elib-node-set-right (dll-get-dummy-node dll) (dll-get-dummy-node dll)))
+
+
+(defun dll-map (map-function dll)
+
+ "Apply MAP-FUNCTION to all elements in the doubly linked list DLL.
+The function is applied to the first element first."
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (node (elib-node-right dummy)))
+
+ (while (not (eq node dummy))
+ (funcall map-function (dll-element dll node))
+ (setq node (elib-node-right node)))))
+
+
+(defun dll-map-reverse (map-function dll)
+
+ "Apply MAP-FUNCTION to all elements in the doubly linked list DLL.
+The function is applied to the last element first."
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (node (elib-node-left dummy)))
+
+ (while (not (eq node dummy))
+ (funcall map-function (dll-element dll node))
+ (setq node (elib-node-left node)))))
+
+
+(defun dll-create-from-list (list)
+
+ "Given an elisp LIST create a doubly linked list with the same elements."
+
+ (let ((dll (dll-create)))
+ (while list
+ (dll-enter-last dll (car list))
+ (setq list (cdr list)))
+ dll))
+
+
+
+(defun dll-sort (dll predicate)
+
+ "Sort the doubly linked list DLL, stably, comparing elements using PREDICATE.
+Returns the sorted list. DLL is modified by side effects.
+PREDICATE is called with two elements of DLL, and should return T
+if the first element is \"less\" than the second."
+
+ (dll-set-from-node-list
+ dll (sort (dll-list-nodes dll)
+ (function (lambda (x1 x2)
+ (funcall predicate
+ (dll-element dll x1)
+ (dll-element dll x2))))))
+ dll)
+
+
+(defun dll-filter (dll predicate)
+
+ "Remove all elements in the doubly linked list DLL for which PREDICATE
+return nil."
+
+ (let* ((dummy (dll-get-dummy-node dll))
+ (node (elib-node-right dummy))
+ next)
+
+ (while (not (eq node dummy))
+ (setq next (elib-node-right node))
+ (if (funcall predicate (dll-element dll node))
+ nil
+ (dll-delete dll node))
+ (setq node next))))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el
new file mode 100644
index 0000000..6c476a3
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/elib-node.el
@@ -0,0 +1,89 @@
+;;;; elib-node.el,v 1.2 1992/04/07 20:49:16 berliner Exp
+;;;; This file implements the nodes used in binary trees and
+;;;; doubly linked lists
+;;;;
+;;;; Copyright (C) 1991 Inge Wallin
+;;;;
+;;;; This file is part of the GNU Emacs lisp library, Elib.
+;;;;
+;;;; 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.
+;;;;
+;;;; Author: Inge Wallin
+;;;;
+
+;;;
+;;; A node is implemented as an array with three elements, using
+;;; (elt node 0) as the left pointer
+;;; (elt node 1) as the right pointer
+;;; (elt node 2) as the data
+;;;
+;;; Some types of trees, e.g. AVL trees, need bigger nodes, but
+;;; as long as the first three parts are the left pointer, the
+;;; right pointer and the data field, these macros can be used.
+;;;
+
+
+(provide 'elib-node)
+
+
+(defmacro elib-node-create (left right data)
+ "Create a tree node from LEFT, RIGHT and DATA."
+ (` (vector (, left) (, right) (, data))))
+
+
+(defmacro elib-node-left (node)
+ "Return the left pointer of NODE."
+ (` (aref (, node) 0)))
+
+
+(defmacro elib-node-right (node)
+ "Return the right pointer of NODE."
+ (` (aref (, node) 1)))
+
+
+(defmacro elib-node-data (node)
+ "Return the data of NODE."
+ (` (aref (, node) 2)))
+
+
+(defmacro elib-node-set-left (node newleft)
+ "Set the left pointer of NODE to NEWLEFT."
+ (` (aset (, node) 0 (, newleft))))
+
+
+(defmacro elib-node-set-right (node newright)
+ "Set the right pointer of NODE to NEWRIGHT."
+ (` (aset (, node) 1 (, newright))))
+
+
+(defmacro elib-node-set-data (node newdata)
+ "Set the data of NODE to NEWDATA."
+ (` (aset (, node) 2 (, newdata))))
+
+
+
+(defmacro elib-node-branch (node branch)
+ "Get value of a branch of a node.
+NODE is the node, and BRANCH is the branch.
+0 for left pointer, 1 for right pointer and 2 for the data."
+ (` (aref (, node) (, branch))))
+
+
+(defmacro elib-node-set-branch (node branch newval)
+ "Set value of a branch of a node.
+NODE is the node, and BRANCH is the branch.
+0 for left pointer, 1 for the right pointer and 2 for the data.
+NEWVAL is new value of the branch."
+ (` (aset (, node) (, branch) (, newval))))
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..27bb57c
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el
@@ -0,0 +1,6 @@
+;;; pcl-cvs-startup.el,v 1.2 1992/04/07 20:49:17 berliner 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)
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..99da369
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el
@@ -0,0 +1,1476 @@
+;;; pcl-cvs.el,v 1.2 1992/04/07 20:49:19 berliner Exp
+;;; pcl-cvs.el -- A Front-end to CVS 1.3 or later. Release 1.02.
+;;; Copyright (C) 1991, 1992 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.
+
+;;; Don't try to use this with CVS 1.2 or earlier. It won't work. Get
+;;; CVS 1.3.
+
+;;; 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/gnu/bin/cvs"
+ "*Full path to the cvs executable.")
+
+(defvar cvs-diff-program "/usr/gnu/bin/diff"
+ "*Full path to the diff program.")
+
+(defvar cvs-rm-program "/usr/gnu/bin/rm"
+ "*Full path to the rm program. Typically /bin/rm.")
+
+;; 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.
+
+;;; END OF THINGS TO CHECK WHEN INSTALLING
+;;; --------------------------------------------------------
+
+(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-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-commit
+command.")
+
+(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-temp-buffer-name "*cvs-tmp*"
+ "*Name of the cvs temporary buffer.
+Output from cvs is placed here by synchronous commands.")
+
+(defvar cvs-cvs-diff-flags nil
+ "*List of strings to use as flags to pass to ``cvs diff''.
+Used by cvs-diff-cvs.
+Set this to '("-u") to get a Unidiff format, or '("-c") to get context diffs.")
+
+(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''.
+Do not confuse with cvs-cvs-diff-flags. Used by cvs-diff-backup.")
+
+(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
+ "*Don't display a Copyright message in the ``*cvs*'' buffer.")
+
+(defvar cvs-startup-message
+ (if cvs-inhibit-copyright-message
+ "PCL-CVS release 1.02"
+ "PCL-CVS release 1.02. Copyright (C) 1992 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-cvs-buffer nil
+ "Internal to pcl-cvs.el.
+This variable exists in the *cvs-commit-message* buffer and names
+the *cvs* buffer.")
+
+;;; 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.
+;;; 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.
+;;; 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.
+;;;
+;;; 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.
+ 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.
+ 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, DIRCHANGE, UNKNOWN, MOVE-AWAY
+or REPOS-MISSING."
+ (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->backup-file (cvs-fileinfo)
+ "Get backup-file 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->backup-file (cvs-fileinfo newval)
+ "Set backup-file 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."
+
+ (display-buffer (get-buffer-create cvs-temp-buffer-name))
+ (set-buffer cvs-temp-buffer-name)
+ (setq buffer-read-only nil)
+ (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))
+
+(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-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.
+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)
+ (let* ((this-dir (file-name-as-directory (expand-file-name directory)))
+ (use-this-window (equal (buffer-name (current-buffer))
+ cvs-buffer-name))
+ (update-buffer (generate-new-buffer
+ (concat (file-name-nondirectory
+ (substring this-dir 0 -1))
+ "-update")))
+ cvs-process args)
+
+ ;; The *cvs* buffer is killed to avoid confusion - is the update ready
+ ;; or not?
+ (if (get-buffer cvs-buffer-name)
+ (kill-buffer cvs-buffer-name))
+
+ ;; Generate "-n update -l".
+ (if local (setq args (list "-l")))
+ (setq args (cons "update" args))
+ (if dont-change-disc (setq args (cons "-n" args)))
+
+ ;; Set up the buffer that receives the output from "cvs update".
+ (if use-this-window
+ (switch-to-buffer update-buffer)
+ (set-buffer update-buffer)
+ (display-buffer update-buffer))
+
+ (setq default-directory this-dir)
+ (setq cvs-process
+ (let ((process-connection-type nil)) ; Use a pipe, not a pty.
+ (apply 'start-process "cvs" update-buffer cvs-program args)))
+
+ (setq mode-line-process
+ (concat ": "
+ (symbol-name (process-status cvs-process))))
+ (set-buffer-modified-p (buffer-modified-p)) ; Update the mode line.
+ (set-process-sentinel cvs-process 'cvs-sentinel)
+
+ ;; Work around a bug in emacs 18.57 and earlier.
+ (setq cvs-buffers-to-delete
+ (cvs-delete-unused-temporary-buffers cvs-buffers-to-delete))))
+
+(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:
+
+\\[cookie-previous-cookie] Move up. \\[cookie-next-cookie] Move down.
+\\[cvs-commit] Commit file. \\[cvs-update-no-prompt] Reupdate directory.
+\\[cvs-mark] Mark file/dir. \\[cvs-unmark] Unmark file/dir.
+\\[cvs-mark-all-files] Mark all files. \\[cvs-unmark-all-files] Unmark all files.
+\\[cvs-find-file] Edit file/run Dired. \\[cvs-find-file-other-window] Find file or run Dired in other window.
+\\[cvs-remove-handled] Remove processed entries. \\[cvs-add-change-log-entry-other-window] Write ChangeLog in other window.
+\\[cvs-add] Add to repository. \\[cvs-remove-file] Remove file.
+\\[cvs-diff-cvs] Diff between base revision. \\[cvs-diff-backup] Diff backup file.
+\\[cvs-acknowledge] Delete line from buffer. \\[cvs-ignore] Add file to the .cvsignore file.
+\\[cvs-log] Run ``cvs log''. \\[cvs-status] Run ``cvs status''.
+
+Entry to this mode runs cvs-mode-hook.
+This description is updated for release 1.02 of pcl-cvs.
+All bindings:
+\\{cvs-mode-map}"
+ (interactive)
+ (setq major-mode 'cvs-mode)
+ (setq mode-name "CVS")
+ (setq buffer-read-only 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))))
+ (cvs-parse-buffer)
+ (setq cvs-buffers-to-delete
+ (cons (process-buffer proc) cvs-buffers-to-delete)))
+ (set-buffer-modified-p (buffer-modified-p)))
+ (if (equal obuf (process-buffer proc))
+ nil
+ (set-buffer (process-buffer proc))
+ (if (< opoint omax)
+ (goto-char opoint))
+ (set-buffer obuf))))))
+
+(defun cvs-skip-line (regexp errormsg &optional arg)
+ "Like forward-line, but check that the skipped line matches REGEXP.
+If it doesn't match REGEXP (error ERRORMSG) is called.
+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
+ (error errormsg))))
+
+(defun cvs-get-current-dir (dirname)
+ "Return current working directory, suitable for cvs-parse-buffer.
+Args: DIRNAME.
+Concatenates default-directory and DIRNAME to form an absolute path."
+ (if (string= "." dirname)
+ (substring default-directory 0 -1)
+ (concat default-directory dirname)))
+
+
+(defun cvs-parse-buffer ()
+ "Parse the current buffer and select a *cvs* buffer.
+Signals an error if unexpected output was detected in the buffer."
+ (goto-char (point-min))
+ (let ((buf (get-buffer-create cvs-buffer-name))
+ (current-dir default-directory)
+ (root-dir default-directory)
+ (parse-buf (current-buffer)))
+
+ (cookie-create
+ buf 'cvs-pp cvs-startup-message ;Se comment above cvs-startup-message.
+ "---------- End -----")
+
+ (cookie-enter-first
+ buf
+ (cvs-create-fileinfo
+ 'DIRCHANGE current-dir
+ nil ""))
+
+ (while (< (point) (point-max))
+ (cond
+
+ ;; CVS is descending a subdirectory.
+
+ ((looking-at "cvs update: Updating \\(.*\\)$")
+ (setq current-dir
+ (cvs-get-current-dir
+ (buffer-substring (match-beginning 1) (match-end 1))))
+
+ ;; Omit empty directories.
+ (if (eq (cvs-fileinfo->type (cookie-last buf))
+ 'DIRCHANGE)
+ (cookie-delete-last buf))
+
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'DIRCHANGE current-dir
+ nil (buffer-substring (match-beginning 0)
+ (match-end 0))))
+ (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"))
+ (cookie-enter-last
+ buf
+ (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))))
+ (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$")
+ (cookie-enter-last
+ buf
+ (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))))
+ (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$")
+ (cookie-enter-last
+ buf
+ (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))))
+ (forward-line 1))
+
+ ((looking-at
+ "cvs update: conflict: removed \\(.*\\) was modified by second party")
+ (cvs-create-fileinfo
+ 'MOD-CONFLICT current-dir
+ (buffer-substring (match-beginning 1) (match-end 1))
+ (buffer-substring (match-beginning 0) (match-end 0)))
+ (forward-line 1))
+
+ ((looking-at "cvs update: in directory ")
+ (let ((start (point)))
+ (forward-line 1)
+ (cvs-skip-line
+ (regexp-quote "cvs [update aborted]: there is no repository ")
+ "Unexpected cvs output.")
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'REPOS-MISSING current-dir
+ nil
+ (buffer-substring start (point))))))
+
+ ;; The file is copied from the repository.
+
+ ((looking-at "U \\(.*\\)$")
+ (cookie-enter-last
+ buf
+ (let ((fileinfo
+ (cvs-create-fileinfo
+ 'UPDATED current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0) (match-end 0)))))
+ (cvs-set-fileinfo->handled fileinfo t)
+ fileinfo))
+ (forward-line 1))
+
+ ;; The file is modified by the user, and untouched in the repository.
+
+ ((looking-at "M \\(.*\\)$")
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'MODIFIED current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0) (match-end 0))))
+ (forward-line 1))
+
+ ;; The file is "cvs add"ed, but not "cvs ci"ed.
+
+ ((looking-at "A \\(.*\\)$")
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'ADDED current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0) (match-end 0))))
+ (forward-line 1))
+
+ ;; The file is "cvs remove"ed, but not "cvs ci"ed.
+
+ ((looking-at "R \\(.*\\)$")
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'REMOVED current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0) (match-end 0))))
+ (forward-line 1))
+
+ ;; Unknown file.
+
+ ((looking-at "? \\(.*\\)$")
+ (cookie-enter-last
+ buf
+ (cvs-create-fileinfo
+ 'UNKNOWN current-dir
+ (file-name-nondirectory
+ (buffer-substring (match-beginning 1) (match-end 1)))
+ (buffer-substring (match-beginning 0) (match-end 0))))
+ (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 "^RCS file: .*$" "Parse error.")
+ (setq initial-revision
+ (cvs-skip-line "^retrieving revision \\(.*\\)$"
+ "Unexpected output from cvs." 1))
+ (cvs-skip-line "^retrieving revision .*$"
+ "Unexpected output from cvs.")
+
+ ;; Get the file name from the next line.
+
+ (setq
+ filename
+ (cvs-skip-line
+ "^Merging differences between [0-9.]+ and [0-9.]+ into \\(.*\\)$"
+ "Unexpected output from cvs."
+ 1))
+
+ (cond
+
+ ;; The file was successfully merged.
+
+ ((looking-at "^M ")
+ (forward-line 1)
+ (let ((fileinfo
+ (cvs-create-fileinfo
+ 'MERGED current-dir
+ filename
+ (buffer-substring complex-start (point)))))
+ (cvs-set-fileinfo->backup-file
+ fileinfo
+ (concat cvs-bakprefix filename "." initial-revision))
+ (cookie-enter-last
+ buf fileinfo)))
+
+ ;; A conflicting merge.
+
+ (t
+ (cvs-skip-line "^merge: overlaps during merge$"
+ "Unexpected output from cvs.")
+ (cvs-skip-line "^cvs update: conflicts found in "
+ "Unexpected output from cvs.")
+ (cvs-skip-line "^C " "Unexpected cvs output.")
+ (let ((fileinfo
+ (cvs-create-fileinfo
+ 'CONFLICT current-dir
+ filename
+ (buffer-substring complex-start (point)))))
+
+ (cvs-set-fileinfo->backup-file
+ fileinfo
+ (concat cvs-bakprefix filename "." initial-revision))
+
+ (cookie-enter-last buf fileinfo))))))))
+
+ ;; All parsing is done.
+
+ ;; If the last entry is a directory, remove it.
+ (if (eq (cvs-fileinfo->type (cookie-last buf))
+ 'DIRCHANGE)
+ (cookie-delete-last buf))
+
+ (set-buffer buf)
+ (cvs-mode)
+ (setq cookie-last-tin (cookie-nth buf 0))
+ (goto-char (point-min))
+ (cookie-previous-cookie buf (point-min) 1)
+ (setq default-directory root-dir)
+ (if (get-buffer-window parse-buf)
+ (set-window-buffer (get-buffer-window parse-buf) buf)
+ (display-buffer buf))))
+
+
+(defun cvs-pp (fileinfo)
+ "Pretty print FILEINFO into a string."
+
+ (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")))
+ (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 '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."))
+ (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 " " 'cookie-next-cookie)
+ (define-key cvs-mode-map "?" 'describe-mode)
+ (define-key cvs-mode-map "A" 'cvs-add-change-log-entry-other-window)
+ (define-key cvs-mode-map "M" 'cvs-mark-all-files)
+ (define-key cvs-mode-map "U" 'cvs-unmark-all-files)
+ (define-key cvs-mode-map "\C-?" 'cvs-unmark-up)
+ (define-key cvs-mode-map "\C-n" 'cookie-next-cookie)
+ (define-key cvs-mode-map "\C-p" 'cookie-previous-cookie)
+ (define-key cvs-mode-map "a" 'cvs-add)
+ (define-key cvs-mode-map "b" 'cvs-diff-backup)
+ (define-key cvs-mode-map "c" 'cvs-commit)
+ (define-key cvs-mode-map "d" 'cvs-diff-cvs)
+ (define-key cvs-mode-map "f" 'cvs-find-file)
+ (define-key cvs-mode-map "g" 'cvs-update-no-prompt)
+ (define-key cvs-mode-map "i" 'cvs-ignore)
+ (define-key cvs-mode-map "l" 'cvs-log)
+ (define-key cvs-mode-map "m" 'cvs-mark)
+ (define-key cvs-mode-map "n" 'cookie-next-cookie)
+ (define-key cvs-mode-map "o" 'cvs-find-file-other-window)
+ (define-key cvs-mode-map "p" 'cookie-previous-cookie)
+ (define-key cvs-mode-map "r" 'cvs-remove-file)
+ (define-key cvs-mode-map "s" 'cvs-status)
+ (define-key cvs-mode-map "\C-k" 'cvs-acknowledge)
+ (define-key cvs-mode-map "x" 'cvs-remove-handled)
+ (define-key cvs-mode-map "u" 'cvs-unmark))
+
+
+(defun cvs-get-marked ()
+ "Return a list of all selected tins.
+If there are any marked tins, 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."
+
+ (cond
+ ;; Any marked cookies?
+ ((cookie-collect-tins (current-buffer)
+ 'cvs-fileinfo->marked))
+ ;; Nope.
+ (t
+ (let ((sel (cookie-get-selection
+ (current-buffer) (point) cookie-last-tin)))
+ (cond
+ ;; If a directory is selected, all it members are returned.
+ ((and sel (eq (cvs-fileinfo->type
+ (cookie-cookie (current-buffer) sel))
+ 'DIRCHANGE))
+ (cookie-collect-tins
+ (current-buffer) 'cvs-dir-member-p
+ (cvs-fileinfo->dir (cookie-cookie (current-buffer) 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 (cvs-buf tin)
+ "Return non-nil if TIN is a directory that is empty.
+Args: CVS-BUF TIN."
+ (and (eq (cvs-fileinfo->type (cookie-cookie cvs-buf tin)) 'DIRCHANGE)
+ (or (not (cookie-next cvs-buf tin))
+ (eq (cvs-fileinfo->type (cookie-cookie cvs-buf
+ (cookie-next cvs-buf tin)))
+ 'DIRCHANGE))))
+
+(defun cvs-remove-handled ()
+ "Remove all lines that are handled.
+Empty directories are removed."
+ (interactive)
+ ;; Pass one: remove files that are handled.
+ (cookie-filter (current-buffer)
+ (function
+ (lambda (fileinfo) (not (cvs-fileinfo->handled fileinfo)))))
+ ;; Pass two: remove empty directories.
+ (cookie-filter-tins (current-buffer)
+ (function
+ (lambda (tin)
+ (not (cvs-dir-empty-p (current-buffer) tin))))))
+
+(defun cvs-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 (cookie-get-selection
+ (current-buffer) pos cookie-last-tin))
+ (sel (cookie-cookie (current-buffer) 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.
+ (current-buffer)
+ (cvs-fileinfo->dir sel)))
+ (t
+ (cvs-set-fileinfo->marked sel t)
+ (cookie-invalidate-tins (current-buffer) tin)
+ (cookie-next-cookie (current-buffer) pos 1)))))
+
+
+(defun cvs-committable (tin cvs-buf)
+ "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 (cookie-cookie cvs-buf 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-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)
+ cvs-buf)))
+ (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)
+ (make-local-variable 'cvs-cvs-buffer)
+ (setq cvs-cvs-buffer cvs-buf)
+ (message "Press C-c C-c when you are done editing."))))
+
+
+(defun cvs-edit-done ()
+ "Commit the files to the repository."
+ (interactive)
+ (save-some-buffers)
+ (let ((cc-list cvs-commit-list)
+ (cc-buffer cvs-cvs-buffer)
+ (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...")
+ (cvs-execute-list cc-list cvs-program (list "commit" "-m" msg))
+ (mapcar (function
+ (lambda (tin)
+ (cvs-set-fileinfo->handled (cookie-cookie cc-buffer tin) t)))
+ cc-list)
+ (apply 'cookie-invalidate-tins cc-buffer cc-list)
+ (set-buffer cc-buffer)
+ (if cvs-auto-remove-handled
+ (cvs-remove-handled)))
+
+ (message "Committing... Done."))
+
+
+(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."
+
+ (while tin-list
+ (let ((current-dir (cvs-fileinfo->dir
+ (cookie-cookie cvs-buffer-name
+ (car tin-list))))
+ arg-list arg-str)
+
+ ;; Collect all marked files in this directory.
+
+ (while (and tin-list
+ (string=
+ current-dir
+ (cvs-fileinfo->dir
+ (cookie-cookie cvs-buffer-name (car tin-list)))))
+ (setq arg-list
+ (cons (cvs-fileinfo->file-name
+ (cookie-cookie cvs-buffer-name (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)
+ " ")))
+ (apply 'call-process program nil t t
+ (nconc (copy-sequence constant-args) arg-list))
+ (goto-char (point-max)))))
+
+
+(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
+ (cookie-cookie cvs-buffer-name
+ (car tin-list)))))
+ (arg-list
+ (funcall extractor
+ (cookie-cookie cvs-buffer-name (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-diff-cvs ()
+ "Diff the selected files against the repository.
+The flags the variable cvs-cvs-diff-flags will be passed to ``cvs diff''."
+ (interactive)
+
+ (save-some-buffers)
+ (let ((marked (cvs-get-marked)))
+ (cvs-use-temp-buffer)
+ (message "cvsdiffing...")
+ (cvs-execute-list marked cvs-program (cons "diff" cvs-cvs-diff-flags)))
+ (message "cvsdiffing... Done."))
+
+
+(defun cvs-backup-diffable (tin cvs-buf)
+ "Check if the TIN is backup-diffable.
+It must have a backup file to be diffable."
+ (cvs-fileinfo->backup-file (cookie-cookie cvs-buf tin)))
+
+(defun cvs-diff-backup ()
+ "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.
+
+The flags in cvs-diff-flags will be passed to ``diff''."
+
+ (interactive)
+ (save-some-buffers)
+ (let ((marked (cvs-filter (function cvs-backup-diffable)
+ (cvs-get-marked)
+ (current-buffer))))
+ (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 (null (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->file-name fileinfo)
+ (cvs-fileinfo->backup-file fileinfo)))
+
+(defun cvs-find-file-other-window (pos)
+ "Select a buffer containing the file in another window.
+Args: POS"
+ (interactive "d")
+ (save-some-buffers)
+ (let* ((cookie-last-tin
+ (cookie-get-selection (current-buffer) pos cookie-last-tin))
+ (type (cvs-fileinfo->type (cookie-cookie (current-buffer)
+ cookie-last-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
+ (cookie-cookie (current-buffer) cookie-last-tin))))
+ (dired-other-window default-directory)
+ (set-buffer obuf)
+ (setq default-directory odir)))
+ (t
+ (find-file-other-window (cvs-full-path (current-buffer)
+ cookie-last-tin))))))
+
+(defun cvs-full-path (buffer tin)
+ "Return the full path for the file that is described in TIN.
+Args: BUFFER TIN."
+ (concat
+ (file-name-as-directory
+ (cvs-fileinfo->dir (cookie-cookie buffer tin)))
+ (cvs-fileinfo->file-name (cookie-cookie buffer tin))))
+
+(defun cvs-find-file (pos)
+ "Select a buffer containing the file in another window.
+Args: POS"
+ (interactive "d")
+ (let* ((cvs-buf (current-buffer))
+ (cookie-last-tin (cookie-get-selection cvs-buf pos cookie-last-tin))
+ (fileinfo (cookie-cookie cvs-buf cookie-last-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 cvs-buf cookie-last-tin))))))
+
+(defun cvs-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))))
+ (current-buffer)))
+
+
+(defun cvs-unmark (pos)
+ "Unmark a fileinfo. Args: POS."
+ (interactive "d")
+
+ (let* ((tin (cookie-get-selection
+ (current-buffer) pos cookie-last-tin))
+ (sel (cookie-cookie (current-buffer) 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))))
+ (current-buffer)
+ (cvs-fileinfo->dir sel)))
+ (t
+ (cvs-set-fileinfo->marked sel nil)
+ (cookie-invalidate-tins (current-buffer) tin)
+ (cookie-next-cookie (current-buffer) pos 1)))))
+
+(defun cvs-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))
+ (current-buffer)))
+
+
+(defun cvs-do-removal (cvs-buf tins)
+ "Remove files.
+Args: CVS-BUF TINS.
+CVS-BUF is the cvs buffer. 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 (cookie-cookie cvs-buf tin))
+ (type (cvs-fileinfo->type fileinfo)))
+ (if (not (or (eq type 'REMOVED) (eq type 'CVS-REMOVED)))
+ (progn
+ (delete-file (cvs-full-path cvs-buf tin))
+ (cond
+ ((or (eq type 'UNKNOWN) (eq type 'MOVE-AWAY))
+ (cookie-delete cvs-buf tin))
+ (t
+ (setq files-to-remove (cons tin files-to-remove))
+ (cvs-set-fileinfo->type fileinfo 'REMOVED)
+ (cvs-set-fileinfo->handled fileinfo nil)
+ (cookie-invalidate-tins cvs-buf tin))))))
+ (setq tins (cdr tins)))
+ files-to-remove))
+ (t nil)))
+
+
+
+(defun cvs-remove-file ()
+ "Remove all marked files."
+ (interactive)
+ (let ((files-to-remove (cvs-do-removal (current-buffer) (cvs-get-marked))))
+ (if (null files-to-remove)
+ nil
+ (cvs-use-temp-buffer)
+ (message "removing from repository...")
+ (cvs-execute-list files-to-remove cvs-program '("remove"))
+ (message "removing from repository... done."))))
+
+(defun cvs-acknowledge ()
+ "Remove all marked files from the buffer."
+ (interactive)
+
+ (mapcar (function (lambda (tin)
+ (cookie-delete (current-buffer) tin)))
+ (cvs-get-marked))
+ (setq cookie-last-tin nil))
+
+
+(defun cvs-unmark-up (pos)
+ "Unmark the file on the previous line.
+Takes one argument POS, a buffer position."
+ (interactive "d")
+ (cookie-previous-cookie (current-buffer) pos 1)
+ (cvs-set-fileinfo->marked (cookie-cookie (current-buffer) cookie-last-tin)
+ nil)
+ (cookie-invalidate-tins (current-buffer) cookie-last-tin))
+
+(defun cvs-add-file-update-buffer (cvs-buf tin)
+ "Subfunction to cvs-add. Internal use only.
+Update the display. Return non-nil if `cvs add' should be called on this
+file. Args: CVS-BUF TIN.
+Returns 'ADD or 'RESURRECT."
+ (let ((fileinfo (cookie-cookie cvs-buf tin)))
+ (cond
+ ((eq (cvs-fileinfo->type fileinfo) 'UNKNOWN)
+ (cvs-set-fileinfo->type fileinfo 'ADDED)
+ (cookie-invalidate-tins cvs-buf tin)
+ 'ADD)
+ ((eq (cvs-fileinfo->type fileinfo) 'REMOVED)
+ (cvs-set-fileinfo->type fileinfo 'UPDATED)
+ (cvs-set-fileinfo->handled fileinfo t)
+ (cookie-invalidate-tins cvs-buf 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 cvs-buf (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-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...")
+ (cvs-execute-list resurrect cvs-program '("add"))
+ (message "Done.")))
+
+ (cond (added
+ (message "Adding new files to repository...")
+ (cvs-execute-list added cvs-program (list "add" "-m" msg))
+ (message "Done.")))))
+
+(defun cvs-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
+ (cookie-cookie (current-buffer) tin)) 'UNKNOWN)
+ (cvs-append-to-ignore
+ (cookie-cookie (current-buffer) tin))
+ (cookie-delete (current-buffer) tin)))))
+ (cvs-get-marked))
+ (setq cookie-last-tin nil))
+
+(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")
+ (save-buffer)))
+
+(defun cvs-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 ...")
+ (cvs-execute-list marked cvs-program (cons "status" cvs-status-flags)))
+ (message "Running cvs status ... Done."))
+
+(defun cvs-log ()
+ "Display the cvs log of all selected files."
+ (interactive)
+
+ (let ((marked (cvs-get-marked)))
+ (cvs-use-temp-buffer)
+ (message "Running cvs log ...")
+ (cvs-execute-list marked cvs-program (cons "log" cvs-log-flags)))
+ (message "Running cvs log ... Done."))
+
+
+(defun cvs-insert-full-path (tin)
+ "Insert full path to the file described in TIN."
+ (insert (format "%s\n" (cvs-full-path cvs-buffer-name tin))))
+
+
+(defun cvs-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
+ (cookie-cookie
+ cvs-buf
+ (cookie-get-selection cvs-buf pos cookie-last-tin)))))
+ (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 (cookie-cookie (current-buffer) 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)))
diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info
new file mode 100644
index 0000000..3c0d3c0
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.info
@@ -0,0 +1,1367 @@
+Info file pcl-cvs, produced by Makeinfo, -*- Text -*- from input
+file pcl-cvs.texinfo.
+
+ Copyright (C) 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.
+
+
+File: pcl-cvs, Node: Top, Next: Copying, Prev: (dir), Up: (dir)
+
+ 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.02 of pcl-cvs.
+
+* 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.
+* Reporting bugs and ideas:: Where to report bugs.
+
+* 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
+* Removing handled entries:: Uninteresting lines can easily be removed.
+* Ignoring files:: Telling CVS to ignore generated files.
+* Viewing differences:: Commands to `diff' different versions.
+
+
+File: pcl-cvs, Node: Copying, Next: Installation, Prev: Top, Up: Top
+
+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.
+
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 1. 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.
+
+ 2. 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.
+
+ 3. 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:
+
+ 1. You must cause the modified files to carry prominent
+ notices stating that you changed the files and the date of
+ any change.
+
+ 2. 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.
+
+ 3. 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.
+
+ 4. 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:
+
+ 1. 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,
+
+ 2. 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,
+
+ 3. 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.
+
+ 5. 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.
+
+ 6. 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.
+
+ 7. 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.
+
+ 8. 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.
+
+ 9. 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.
+
+ 10. 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.
+
+ 11. 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
+
+ 12. 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.
+
+ 13. 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.
+
+
+File: pcl-cvs, Node: Installation, Next: About pcl-cvs, Prev: Copying, Up: Top
+
+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 `pcl-cvs.texinfo' as well as an on-line info file. The
+following steps are also described in the 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.
+
+
+File: pcl-cvs, Node: Pcl-cvs installation, Next: On-line manual installation, Prev: Installation, Up: Installation
+
+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. 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.
+
+ 4. 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.
+
+
+File: pcl-cvs, Node: On-line manual installation, Next: Typeset manual installation, Prev: Pcl-cvs installation, Up: Installation
+
+Installation of the on-line manual.
+===================================
+
+ 1. Create the info file `pcl-cvs' 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), or you could use the preformatted
+ info file `pcl-cvs.info' that is included in the distribution
+ (type `cp pcl-cvs.info pcl-cvs').
+
+ 2. Move the info file `pcl-cvs' to your standard info directory.
+ This might be called something like `/usr/gnu/emacs/info'.
+
+ 3. Edit the file `dir' in the info directory and enter one line to
+ contain a pointer to the info file `pcl-cvs'. The line can, for
+ instance, look like this:
+
+ * Pcl-cvs: (pcl-cvs). An Emacs front-end to CVS.
+
+
+File: pcl-cvs, Node: Typeset manual installation, Prev: On-line manual installation, Up: Installation
+
+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.
+
+
+File: pcl-cvs, Node: About pcl-cvs, Next: Getting started, Prev: Installation, Up: Top
+
+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?
+
+
+File: pcl-cvs, Node: Contributors, Next: Archives, Prev: About pcl-cvs, Up: About pcl-cvs
+
+Contributors to pcl-cvs
+=======================
+
+ 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 (*note Reporting bugs and ideas::.).
+
+ The following persons have made contributions to pcl-cvs.
+
+ * Brian Berliner wrote CVS, together with some other contributors.
+ Without his work on CVS this package would be useless...
+
+ * Per Cederqvist wrote most of the otherwise unattributed
+ functions in pcl-cvs as well as all documentation.
+
+ * Inge Wallin (`inge@lysator.liu.se') wrote the skeleton to
+ `pcl-cvs.texinfo', and gave useful comments on it. He also
+ wrote the files `elib-node.el' and `compile-all.el'. The file
+ `cookie.el' was inspired by Inge.
+
+ * Linus Tolke (`linus@lysator.liu.se') contributed useful comments
+ on both the functionality and the documentation.
+
+
+File: pcl-cvs, Node: Archives, Prev: Contributors, Up: About pcl-cvs
+
+Where can I get pcl-cvs?
+========================
+
+ This release of pcl-cvs is included in the CVS 1.3 distribution.
+However, since pcl-cvs has had less time to mature (the first line of
+code was written less than a year ago) it is likely that there will
+be a new release of pcl-cvs before the next release of CVS.
+
+ The latest release of pcl-cvs can be fetched via anonymous ftp
+from `ftp.lysator.liu.se', (IP no. 130.236.254.1) in the directory
+`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.
+
+
+File: pcl-cvs, Node: Getting started, Next: Buffer contents, Prev: About pcl-cvs, Up: Top
+
+Getting started
+***************
+
+ 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 `M-x pcl-cvs RET'. If your emacs
+responds with `[No match]' your system administrator has not
+installed pcl-cvs properly. Try `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 `.emacs' file so that you don't have to type the
+`load-library' command every time you wish to use pcl-cvs:
+
+ (autoload 'cvs-update "pcl-cvs" nil t)
+
+ The function `cvs-update' will ask for a directory. The command
+`cvs update' will be run in that directory. (It should contain
+files that have been checked out from a CVS archive.) The output
+from `cvs' will be parsed and presented in a table in a buffer called
+`*cvs*'. It might look something like this:
+
+ PCL-CVS release 1.02.
+
+ 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 -----
+
+ In this example the three files (`bar', `file.txt' and `newer')
+that are marked with `Updated' have been copied from the CVS
+repository to `/users/ceder/FOO/test/' since someone else have
+checked in newer versions of them. Two files (`namechange' and
+`sub/ChangeLog') have been modified locally, and needs to be checked
+in.
+
+ You can move the cursor up and down in the buffer with `C-n' and
+`C-p' or `n' and `p'. If you press `c' on one of the `Modified'
+files that file will be checked in to the CVS repository. *Note
+Committing changes::. You can press `x' to get rid of the
+"uninteresting" files that have only been `Updated' (and don't
+require any further action from you).
+
+ You can also easily get a `diff' between your modified file and
+the base version that you started from, and you can get the output
+from `cvs log' and `cvs status' on the listed files simply by
+pressing a key (*note Getting info about files::.).
+
+
+File: pcl-cvs, Node: Buffer contents, Next: Commands, Prev: Getting started, Up: Top
+
+Buffer contents
+***************
+
+ The display contains four columns. They contain, from left to
+right:
+
+ * An asterisk when the file is "marked" (*note Selected files::.).
+
+ * The status of the file. See *Note File status::, for more
+ information.
+
+ * A "need to be checked in"-marker (`ci').
+
+ * The file name.
+
+* Menu:
+
+* File status:: The meaning of the second field.
+* Selected files:: How selection works.
+
+
+File: pcl-cvs, Node: File status, Next: Selected files, Prev: Buffer contents, Up: Buffer contents
+
+File status
+===========
+
+ The `file status' field can have the following values:
+
+`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.
+
+`Modified'
+ The file is modified in your working directory, and there
+ was no modification to the same file in the repository.
+
+`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.
+
+`Conflict'
+ A conflict was detected while trying to merge your changes to
+ FILE with changes from the source repository. FILE (the copy
+ in your working directory) is now the output of the `rcsmerge'
+ command on the two versions; an unmodified copy of your file is
+ also in your working directory, with the name `.#FILE.VERSION',
+ where VERSION is the RCS revision that your modified file
+ started from. *Note Viewing differences::, for more details.
+
+`Added'
+ The file has been added by you, but it still needs to be
+ checked in to the repository.
+
+`Removed'
+ The file has been removed by you, but it needs to be checked in
+ to the repository. You can resurrect it by typing `a' (*note
+ Adding and removing files::.).
+
+`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.
+
+ There are also a few special cases, that rarely occur, which have
+longer strings in the fields:
+
+`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.
+
+`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 *note Adding and removing files::.).
+
+`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 `a' to
+ resurrect the file (see *note Adding and removing files::.).
+
+`Move away FILE - it is in the way'
+ For some reason CVS does not like the file FILE. Rename or
+ remove it.
+
+`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.
+
+
+File: pcl-cvs, Node: Selected files, Prev: File status, Up: Buffer contents
+
+Selected files
+==============
+
+ Many of the commands works on the current set of "selected" files.
+
+ * If there are any files that are marked they constitute the set
+ of selected files.
+
+ * Otherwise, if the cursor points to a file, that file is the
+ selected file.
+
+ * Otherwise, if the cursor points to a directory, all the files
+ in that directory that appears in the buffer are the selected
+ files.
+
+ This scheme might seem a little complicated, but once one get
+used to it, it is quite powerful.
+
+ *Note Marking files:: tells how you mark and unmark files.
+
+
+File: pcl-cvs, Node: Commands, Next: Customization, Prev: Buffer contents, Up: Top
+
+Commands
+********
+
+ The nodes in this menu contains explanations about all the
+commands that you can use in pcl-cvs. They are grouped together by
+type.
+
+* 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
+* Removing handled entries:: Uninteresting lines can easily be removed.
+* Ignoring files:: Telling CVS to ignore generated files.
+* Viewing differences:: Commands to `diff' different versions.
+
+
+File: pcl-cvs, Node: Updating the directory, Next: Movement commands, Prev: Commands, Up: Commands
+
+Updating the directory
+======================
+
+`M-x cvs-update'
+ Run a `cvs update' command. You will be asked for the
+ directory in which the `cvs update' will be run. The output
+ will be parsed by pcl-cvs, and the result printed in the
+ `*cvs*' buffer (see *note Buffer contents::. for a description
+ of the contents).
+
+ By default, `cvs-update' will descend recursively into
+ subdirectories. You can avoid that behavior by giving a prefix
+ argument to it (e.g., by typing `C-u M-x cvs-update RET').
+
+ All other commands in pcl-cvs requires that you have a `*cvs*'
+ buffer. This is the command that you use to get one.
+
+`g'
+ This will run `cvs update' again. It will always use the same
+ buffer that was used with the previous `cvs update'. Give a
+ prefix argument to avoid descending into subdirectories. This
+ runs the command `cvs-update-no-prompt'.
+
+
+File: pcl-cvs, Node: Movement commands, Next: Marking files, Prev: Updating the directory, Up: Commands
+
+Movement Commands
+=================
+
+ 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:
+
+`SPC'
+`C-n'
+`n'
+ These keys move the cursor one file forward, towards the end of
+ the buffer (`cookie-next-cookie').
+
+`C-p'
+`p'
+ These keys move one file backward, towards the beginning of the
+ buffer (`cookie-previous-cookie').
+
+
+File: pcl-cvs, Node: Marking files, Next: Committing changes, Prev: Movement commands, Up: Commands
+
+Marking files
+=============
+
+ Pcl-cvs works on a set of "selected files" (*note Selected
+files::.). You can mark and unmark files with these commands:
+
+`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. (`cvs-mark').
+
+`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.
+ (`cvs-unmark').
+
+`M'
+ Mark *all* files in the buffer (`cvs-mark-all-files').
+
+`U'
+ Unmark *all* files (`cvs-unmark-all-files').
+
+`DEL'
+ Unmark the file on the previous line, and move point to that
+ line (`cvs-unmark-up').
+
+
+File: pcl-cvs, Node: Committing changes, Next: Editing files, Prev: Marking files, Up: Commands
+
+Committing changes
+==================
+
+`c'
+ All files that have a "need to be checked in"-marker (*note
+ Buffer contents::.) can be checked in with the `c' command. It
+ checks in all selected files (*note Selected files::.) (except
+ those who lack the "ci"-marker - they are ignored). Pressing
+ `c' causes `cvs-commit' to be run.
+
+ When you press `c' you will get a buffer called
+ `*cvs-commit-message*'. Enter the log message for the file(s)
+ in it. When you are ready you should press `C-c C-c' to
+ actually commit the files (using `cvs-edit-done').
+
+ Normally the `*cvs-commit-message*' buffer will retain the log
+ message from the previous commit, but if the variable
+ `cvs-erase-input-buffer' is set to a non-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 `C-w'
+ (`kill-region').
+
+
+File: pcl-cvs, Node: Editing files, Next: Getting info about files, Prev: Committing changes, Up: Commands
+
+Editing files
+=============
+
+ 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.
+
+`f'
+ Find the file that the cursor points to. Run `dired'
+
+ (*note Dired: (Emacs)Dired.)
+
+ if the cursor points to a directory (`cvs-find-file').
+
+`o'
+ Like `f', but use another window (`cvs-find-file-other-window').
+
+`A'
+ Invoke `add-change-log-entry-other-window' to edit a
+ `ChangeLog' file. The `ChangeLog' will be found in the
+ directory of the file the cursor points to.
+ (`cvs-add-change-log-entry-other-window').
+
+
+File: pcl-cvs, Node: Getting info about files, Next: Adding and removing files, Prev: Editing files, Up: Commands
+
+Getting info about files
+========================
+
+ Both of the following commands can be customized. *Note
+Customization::.
+
+`l'
+ Run `cvs log' on all selected files, and show the result in a
+ temporary buffer (`cvs-log').
+
+`s'
+ Run `cvs status' on all selected files, and show the result in a
+ temporary buffer (`cvs-status').
+
+
+File: pcl-cvs, Node: Adding and removing files, Next: Removing handled entries, Prev: Getting info about files, Up: Commands
+
+Adding and removing files
+=========================
+
+ The following commands are available to make it easy to add and
+remove files from the CVS repository.
+
+`a'
+ Add all selected files. This command can be used on `Unknown'
+ files (see *note File status::.). The status of the file will
+ change to `Added', and you will have to use `c' (`cvs-commit',
+ see *note Committing changes::.) to really add the file to the
+ repository.
+
+ This command can also be used on `Removed' files (before you
+ commit them) to resurrect them.
+
+ Selected files that are neither `Unknown' nor `Removed' will be
+ ignored by this command.
+
+ The command that is run is `cvs-add'.
+
+`r'
+ This command removes the selected files (after prompting for
+ confirmation). The files are `rm'ed from your directory and
+ (unless the status was `Unknown'; *note File status::.) they
+ will also be `cvs remove'd. If the files were `Unknown' they
+ will disappear from the buffer. Otherwise their status will
+ change to `Removed', and you must use `c' (`cvs-commit', *note
+ Committing changes::.) to commit the removal.
+
+ The command that is run is `cvs-remove-file'.
+
+
+File: pcl-cvs, Node: Removing handled entries, Next: Ignoring files, Prev: Adding and removing files, Up: Commands
+
+Removing handled entries
+========================
+
+`x'
+ This command allows you to remove all entries that you have
+ processed. More specifically, the lines for `Updated' files
+ (*note File status::. and files that have been checked in
+ (*note 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 `cvs-remove-handled'. If
+ `cvs-auto-remove-handled' is set to non-`nil' this will
+ automatically be performed after every commit.
+
+`C-k'
+ This command can be used for lines that `cvs-remove-handled'
+ would not delete, but that you want to delete
+ (`cvs-acknowledge').
+
+
+File: pcl-cvs, Node: Ignoring files, Next: Viewing differences, Prev: Removing handled entries, Up: Commands
+
+Ignoring files
+==============
+
+`i'
+ Arrange so that CVS will ignore the selected files. The file
+ names are added to the `.cvsignore' file in the corresponding
+ directory. If the `.cvsignore' doesn't exist it will be
+ created.
+
+ The `.cvsignore' file should normally be added to the
+ repository, but you could ignore it also if you like it better
+ that way.
+
+ This runs `cvs-ignore'.
+
+
+File: pcl-cvs, Node: Viewing differences, Prev: Ignoring files, Up: Commands
+
+Viewing differences
+===================
+
+`d'
+ Display a `cvs diff' between the selected files and the RCS
+ version that they are based on. *Note Customization::
+ describes how you can send flags to `cvs diff'. (The function
+ that does the job is `cvs-diff-cvs').
+
+`b'
+ If CVS finds a conflict while merging two versions of a file
+ (during a `cvs update', *note Updating the directory::.) it
+ will save the original file in a file called `.#FILE.VERSION'
+ where FILE is the name of the file, and VERSION is the RCS
+ version number that your file was based on.
+
+ With the `b' command you can run a `diff' on the files
+ `.#FILE.VERSION' and `FILE'. You can get a context- or Unidiff
+ by setting `cvs-diff-flags' - *note Customization::.. This
+ command only works on files that have status `Conflict' or
+ `Merged'. The name of the command is `cvs-diff-backup'.
+
+
+File: pcl-cvs, Node: Customization, Next: Future enhancements, Prev: Commands, Up: Top
+
+Customization
+*************
+
+ If you have an idea about any customization that would be handy
+but isn't present in this list, please tell me! *Note Reporting
+bugs and ideas:: for info on how to reach me.
+
+`cvs-erase-input-buffer'
+ If set to anything else than `nil' the edit buffer will be
+ erased before you write the log message (*note Committing
+ changes::.).
+
+`cvs-inhibit-copyright-message'
+ The copyright message that is displayed on startup can be
+ annoying after a while. Set this variable to `t' if you want
+ to get rid of it. (But don't set this to `t' in the system
+ defaults file - new users should see this message at least
+ once).
+
+`cvs-cvs-diff-flags'
+ A list of strings to pass as arguments to the `cvs diff'
+ program. This is used by `cvs-diff-cvs' (key `d', *note
+ Viewing differences::.). If you prefer the Unidiff format you
+ could add this line to your `.emacs' file:
+
+ (setq cvs-cvs-diff-flags '("-u"))
+
+`cvs-diff-flags'
+ Like `cvs-cvs-diff-flags', but passed to `diff'. This is used
+ by `cvs-diff-backup' (key `b', *note Viewing differences::.).
+
+`cvs-log-flags'
+ List of strings to send to `cvs log'. Used by `cvs-log' (key
+ `l', *note Getting info about files::.).
+
+`cvs-status-flags'
+ List of strings to send to `cvs status'. Used by `cvs-status'
+ (key `s', *note Getting info about files::.).
+
+`cvs-auto-remove-handled'
+ If this variable is set to any non-`nil' value
+ `cvs-remove-handled' will be called every time you check in
+ files, after the check-in is ready. *Note Removing handled
+ entries::.
+
+
+File: pcl-cvs, Node: Future enhancements, Next: Reporting bugs and ideas, Prev: Customization, Up: Top
+
+Future enhancements
+*******************
+
+ Pcl-cvs is still under development and needs a number of
+enhancements to be called complete. Here is my current wish-list
+for future releases of pcl-cvs:
+
+ * Dired support. I have an experimental `dired-cvs.el' that works
+ together with CVS 1.2. Unfortunately I wrote it on top of a
+ non-standard `dired.el', so it must be rewritten.
+
+ * It should be possible to run commands such as `cvs log', `cvs
+ status' and `cvs commit' directly from a buffer containing a
+ file, instead of having to `cvs-update'. If the directory
+ contains many files the `cvs-update' can take quite some time,
+ especially on a slow machine.
+
+ 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 *Note
+Reporting bugs and ideas:: for information about how to reach me.
+
+
+File: pcl-cvs, Node: Reporting bugs and ideas, Next: Function and Variable Index, Prev: Future enhancements, Up: Top
+
+Reporting bugs and ideas
+************************
+
+ If you find a bug or misfeature, don't hesitate to tell me! Send
+email to `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!
+
+
+File: pcl-cvs, Node: Function and Variable Index, Next: Concept Index, Prev: Reporting bugs and ideas, Up: Top
+
+Function and Variable Index
+***************************
+
+* Menu:
+
+* cookie-next-cookie: Movement commands.
+* cookie-previous-cookie: Movement commands.
+* cvs-acknowledge: Removing handled entries.
+* cvs-add: Adding and removing files.
+* cvs-add-change-log-entry-other-window: Editing files.
+* cvs-auto-remove-handled (variable): Customization.
+* cvs-commit: Committing changes.
+* cvs-cvs-diff-flags (variable): Customization.
+* cvs-diff-backup: Viewing differences.
+* cvs-diff-cvs: Viewing differences.
+* cvs-diff-flags (variable): Customization.
+* cvs-erase-input-buffer (variable): Committing changes.
+* cvs-erase-input-buffer (variable): Customization.
+* cvs-find-file: Editing files.
+* cvs-find-file-other-window: Editing files.
+* cvs-inhibit-copyright-message (variable): Customization.
+* cvs-log: Getting info about files.
+* cvs-log-flags (variable): Customization.
+* cvs-mark: Marking files.
+* cvs-mark-all-files: Marking files.
+* cvs-remove-file: Adding and removing files.
+* cvs-remove-handled: Removing handled entries.
+* cvs-status: Getting info about files.
+* cvs-status-flags (variable): Customization.
+* cvs-unmark: Marking files.
+* cvs-unmark-all-files: Marking files.
+* cvs-unmark-up: Marking files.
+* cvs-update: Updating the directory.
+* cvs-update-no-prompt: Updating the directory.
+
+
+File: pcl-cvs, Node: Concept Index, Next: Key Index, Prev: Function and Variable Index, Up: Top
+
+Concept Index
+*************
+
+* Menu:
+
+* About pcl-cvs: About pcl-cvs.
+* Active files: Selected files.
+* Added (file status): File status.
+* Adding files: Adding and removing files.
+* Archives: Archives.
+* Author, how to reach: Reporting bugs and ideas.
+* Authors: Contributors.
+* Automatically remove handled files: Customization.
+* Buffer contents: Buffer contents.
+* Bugs, how to report them: Reporting bugs and ideas.
+* Ci: Committing changes.
+* Commit buffer: Committing changes.
+* Committing changes: Committing changes.
+* Conflict (file status): File status.
+* Conflicts, how to resolve them: Viewing differences.
+* Context diff, how to get: Customization.
+* Contributors: Contributors.
+* Copyright message, getting rid of it: Customization.
+* Customization: Customization.
+* Deleting files: Adding and removing files.
+* Diff: Viewing differences.
+* Dired: Editing files.
+* Edit buffer: Committing changes.
+* Editing files: Editing files.
+* Email archives: Archives.
+* Email to the author: Reporting bugs and ideas.
+* Enhancements: Future enhancements.
+* Erasing commit message: Committing changes.
+* Erasing the input buffer: Customization.
+* Example run: Getting started.
+* Expunging uninteresting entries: Removing handled entries.
+* File selection: Selected files.
+* File status: File status.
+* Finding files: Editing files.
+* Ftp-sites: Archives.
+* Generating a typeset manual: Typeset manual installation.
+* Generating the on-line manual: On-line manual installation.
+* Getting pcl-cvs: Archives.
+* Getting rid of the Copyright message.: Customization.
+* Getting rid of uninteresting lines: Removing handled entries.
+* Getting status: Getting info about files.
+* Handled lines, removing them: Removing handled entries.
+* Info-file (how to generate): On-line manual installation.
+* Inhibiting the Copyright message.: Customization.
+* Installation: Installation.
+* Installation of elisp files: Pcl-cvs installation.
+* Installation of on-line manual: On-line manual installation.
+* Installation of typeset manual: Typeset manual installation.
+* Introduction: Getting started.
+* Invoking dired: Editing files.
+* Loading files: Editing files.
+* Log (RCS/cvs command): Getting info about files.
+* Manual installation (on-line): On-line manual installation.
+* Manual installation (typeset): Typeset manual installation.
+* Marked files: Selected files.
+* Marking files: Marking files.
+* Merged (file status): File status.
+* Modified (file status): File status.
+* Move away FILE - it is in the way (file status): File status.
+* Movement Commands: Movement commands.
+* On-line manual (how to generate): On-line manual installation.
+* Printing a manual: Typeset manual installation.
+* Putting files under CVS control: Adding and removing files.
+* Removed (file status): File status.
+* Removed by you, changed in repository (file status): File status.
+* Removed from repository (file status): File status.
+* Removed from repository, changed by you (file status): File status.
+* Removing files: Adding and removing files.
+* Removing uninteresting (processed) lines: Removing handled entries.
+* Reporting bugs and ideas: Reporting bugs and ideas.
+* Resurrecting files: Adding and removing files.
+* Selected files: Selected files.
+* Selecting files (commands to mark files): Marking files.
+* Sites: Archives.
+* Status (cvs command): Getting info about files.
+* TeX - generating a typeset manual: Typeset manual installation.
+* This repository is missing!... (file status): File status.
+* Unidiff, how to get: Customization.
+* Uninteresting entries, getting rid of them: Removing handled entries.
+* Unknown (file status): File status.
+* Updated (file status): File status.
+* Variables, list of all: Customization.
+* Viewing differences: Viewing differences.
+
+
+File: pcl-cvs, Node: Key Index, Prev: Concept Index, Up: Top
+
+Key Index
+*********
+
+* Menu:
+
+* A - add ChangeLog entry: Editing files.
+* C-k - remove selected entries: Removing handled entries.
+* C-n - Move down one file: Movement commands.
+* C-p - Move up one file: Movement commands.
+* DEL - unmark previous file: Marking files.
+* M - marking all files: Marking files.
+* SPC - Move down one file: Movement commands.
+* U - unmark all files: Marking files.
+* a - add a file: Adding and removing files.
+* b - diff backup file: Viewing differences.
+* c - commit files: Committing changes.
+* d - run cvs diff: Viewing differences.
+* f - find file or directory: Editing files.
+* g - Rerun cvs update: Updating the directory.
+* l - run cvs log: Getting info about files.
+* m - marking a file: Marking files.
+* n - Move down one file: Movement commands.
+* o - find file in other window: Editing files.
+* p - Move up on file: Movement commands.
+* r - remove a file: Adding and removing files.
+* s - run cvs status: Getting info about files.
+* u - unmark a file: Marking files.
+* x - remove processed entries: Removing handled entries.
+
+
+
+Tag Table:
+Node: Top1004
+Node: Copying3396
+Node: Installation22716
+Node: Pcl-cvs installation23507
+Node: On-line manual installation25291
+Node: Typeset manual installation26310
+Node: About pcl-cvs27048
+Node: Contributors27417
+Node: Archives28440
+Node: Getting started29287
+Node: Buffer contents31728
+Node: File status32277
+Node: Selected files35303
+Node: Commands35976
+Node: Updating the directory37018
+Node: Movement commands38043
+Node: Marking files38629
+Node: Committing changes39456
+Node: Editing files40502
+Node: Getting info about files41335
+Node: Adding and removing files41805
+Node: Removing handled entries43145
+Node: Ignoring files44058
+Node: Viewing differences44593
+Node: Customization45595
+Node: Future enhancements47326
+Node: Reporting bugs and ideas48394
+Node: Function and Variable Index48842
+Node: Concept Index50743
+Node: Key Index55865
+
+End Tag Table
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..5ad8db1
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo
@@ -0,0 +1,1437 @@
+\input texinfo @c -*-texinfo-*-
+
+@comment pcl-cvs.texinfo,v 1.2 1992/04/07 20:49:23 berliner 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
+@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.02
+@comment -release-
+@sp 3
+@center Per Cederqvist
+@sp 3
+@center last updated 29 Mar 1992
+@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.02 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.
+* Reporting bugs and ideas:: Where to report bugs.
+
+* 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
+* 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.
+@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
+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{Reporting bugs and ideas}).
+
+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
+
+@end itemize
+
+
+@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
+
+This release of pcl-cvs is included in the CVS 1.3 distribution.
+However, since pcl-cvs has had less time to mature (the first line of
+code was written less than a year ago) it is likely that there will be a
+new release of pcl-cvs before the next release of CVS.
+
+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 pcl-cvs 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.02.
+@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
+* 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.
+@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-update-no-prompt
+@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
+
+@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-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 U - unmark all files
+@kindex DEL - unmark previous file
+@findex cvs-mark
+@findex cvs-unmark
+@findex cvs-mark-all-files
+@findex cvs-unmark-all-files
+@findex cvs-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-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-unmark}).@refill
+
+@item M
+Mark @emph{all} files in the buffer (@code{cvs-mark-all-files}).
+
+@item U
+Unmark @emph{all} files (@code{cvs-unmark-all-files}).
+
+@item @key{DEL}
+Unmark the file on the previous line, and move point to that line
+(@code{cvs-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-commit
+@kindex c - commit files
+@vindex cvs-erase-input-buffer (variable)
+@cindex Commit buffer
+@cindex Edit buffer
+@cindex Erasing commit message
+
+@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-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-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
+@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-find-file
+@findex cvs-find-file-other-window
+@findex cvs-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-find-file}).@refill
+
+@item o
+Like @kbd{f}, but use another window
+(@code{cvs-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-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-log
+@findex cvs-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-log}).
+
+@item s
+Run @samp{cvs status} on all selected files, and show the result in a
+temporary buffer (@code{cvs-status}).
+@end table
+
+@node Adding and removing files, Removing handled entries, 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-add
+@findex cvs-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-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-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-commit},
+@pxref{Committing changes}) to commit the removal.@refill
+
+The command that is run is @code{cvs-remove-file}.
+@end table
+
+@node Removing handled entries, Ignoring files, Adding and removing files, 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-remove-handled
+@findex cvs-acknowledge
+
+@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-remove-handled}. If
+@samp{cvs-auto-remove-handled} is set to non-@samp{nil} this will
+automatically be performed after every commit.@refill
+
+@item C-k
+This command can be used for lines that @samp{cvs-remove-handled} would
+not delete, but that you want to delete (@code{cvs-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-ignore}.
+@end table
+
+@node Viewing differences, , 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-diff-cvs
+@findex cvs-diff-backup
+
+@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}. (The function that does the job is
+@code{cvs-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.
+
+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}. The name of the command is
+@code{cvs-diff-backup}. @refill
+@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-cvs-diff-flags (variable)
+@vindex cvs-diff-flags (variable)
+@vindex cvs-log-flags (variable)
+@vindex cvs-status-flags (variable)
+@vindex cvs-auto-remove-handled (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
+
+If you have an idea about any customization that would be handy but
+isn't present in this list, please tell me! @xref{Reporting bugs and
+ideas} for info on how to reach me.@refill
+
+@table @samp
+@item cvs-erase-input-buffer
+If set to anything else than @samp{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-cvs-diff-flags
+A list of strings to pass as arguments to the @samp{cvs diff} program.
+This is used by @samp{cvs-diff-cvs} (key @kbd{d}, @pxref{Viewing
+differences}). If you prefer the Unidiff format you could add this line
+to your @file{.emacs} file:@refill
+
+@example
+(setq cvs-cvs-diff-flags '("-u"))
+@end example
+
+@item cvs-diff-flags
+Like @samp{cvs-cvs-diff-flags}, but passed to @samp{diff}. This is used
+by @samp{cvs-diff-backup} (key @kbd{b}, @pxref{Viewing differences}).
+
+@item cvs-log-flags
+List of strings to send to @samp{cvs log}. Used by @samp{cvs-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-status}
+(key @kbd{s}, @pxref{Getting info about files}).
+
+@item cvs-auto-remove-handled
+If this variable is set to any non-@samp{nil} value
+@samp{cvs-remove-handled} will be called every time you check in files,
+after the check-in is ready. @xref{Removing handled entries}.@refill
+
+@end table
+@node Future enhancements, Reporting bugs and ideas, 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. Here is my current wish-list for future releases of
+pcl-cvs:
+
+@itemize @bullet
+@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
+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.
+@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{Reporting bugs and
+ideas} for information about how to reach me.@refill
+
+
+@node Reporting bugs and ideas, Function and Variable Index, Future enhancements, Top
+@comment node-name, next, previous, up
+@chapter Reporting bugs and ideas
+@cindex Reporting bugs and ideas
+@cindex Bugs, how to report them
+@cindex Author, how to reach
+@cindex Email to the author
+
+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!
+
+
+@node Function and Variable Index, Concept Index, Reporting bugs and ideas, 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 b/gnu/usr.bin/cvs/contrib/rcs-to-cvs
new file mode 100644
index 0000000..1a241b9
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/rcs-to-cvs
@@ -0,0 +1,208 @@
+#!/bin/csh
+#
+# rcs-to-cvs,v 1.3 1992/04/10 03:04:25 berliner Exp
+# Contributed by Per Cederqvist <ceder@lysator.liu.se>.
+#
+# Copyright (c) 1989, 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.0 kit.
+#
+#############################################################################
+# #
+# This script is used to check in sources that previously was under RCS or #
+# no source control system. #
+# #
+# Usage: rcs-to-cvs repository #
+# #
+# The repository is the directory where the sources should #
+# be deposited.
+# #
+# checkin 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 0.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. #
+# #
+#############################################################################
+
+set vbose = 0
+set message = ""
+set cvsbin = /usr/gnu/bin
+set rcsbin = /usr/gnu/bin
+set grep = /bin/grep
+set message_file = /usr/tmp/checkin.$$
+set got_one = 0
+
+if ( $#argv < 1 ) then
+ echo "Usage: rcs-to-cvs [-v] [-m message] [-f message_file] repository"
+ exit 1
+endif
+while ( $#argv )
+ switch ( $argv[1] )
+ case -v:
+ set vbose = 1
+ breaksw
+ case -m:
+ shift
+ echo $argv[1] > $message_file
+ set got_one = 1
+ breaksw
+ case -f:
+ shift
+ set message_file = $argv[1]
+ set got_one = 2
+ breaksw
+ default:
+ break
+ endsw
+ shift
+end
+if ( $#argv < 1 ) then
+ echo "Usage: rcs-to-cvs [-v] [-m message] [-f message_file] repository"
+ exit 1
+endif
+set repository = $argv[1]
+shift
+
+if ( ! $?CVSROOT ) then
+ echo "Please set the environmental variable CVSROOT to the root"
+ echo " of the tree you wish to update"
+ exit 1
+endif
+
+if ( $got_one == 0 ) then
+ echo "Please Edit this file to contain the RCS log information" >$message_file
+ echo "to be associated with this file (please remove these lines)">>$message_file
+ if ( $?EDITOR ) then
+ $EDITOR $message_file > /dev/tty
+ else
+ /usr/ucb/vi $message_file > /dev/tty
+ endif
+ set got_one = 1
+endif
+
+umask 22
+
+set update_dir = ${CVSROOT}/${repository}
+if ( -d SCCS ) then
+ echo SCCS files detected!
+ exit 1
+endif
+if ( -d RCS ) then
+ $rcsbin/co RCS/* >& /dev/null
+endif
+foreach name ( * .[a-zA-Z0-9]* )
+ echo $name
+ if ( "$name" == SCCS ) then
+ continue
+ endif
+ if ( "$name" == RCS ) then
+ continue
+ endif
+ if ( $vbose ) then
+ echo "Updating ${repository}/${name}"
+ endif
+ if ( -d "$name" ) then
+ if ( ! -d "${update_dir}/${name}" ) then
+ echo "WARNING: Creating new directory ${repository}/${name}"
+ mkdir "${update_dir}/${name}"
+ if ( $status ) then
+ echo "ERROR: mkdir failed - aborting"
+ exit 1
+ endif
+ endif
+ chdir "$name"
+ if ( $status ) then
+ echo "ERROR: Couldn\'t chdir to "$name" - aborting"
+ exit 1
+ endif
+ if ( $vbose ) then
+ rcs-to-cvs -v -f $message_file "${repository}/${name}"
+ else
+ rcs-to-cvs -f $message_file "${repository}/${name}"
+ endif
+ if ( $status ) then
+ exit 1
+ endif
+ chdir ..
+ else # if not directory
+ if ( ! -f "$name" ) then
+ echo "WARNING: "$name" is neither a regular file"
+ echo " nor a directory - ignored"
+ continue
+ endif
+ set file = "${update_dir}/${name},v"
+ set new = 0
+ set comment = ""
+ grep -s '\$Log.*\$' "${name}"
+ if ( $status == 0 ) then # If $Log keyword
+ set myext = ${name:e}
+ set knownext = 0
+ foreach xx ( "c" "csh" "e" "f" "h" "l" "mac" "me" "mm" "ms" "p" "r" "red" "s" "sh" "sl" "cl" "ml" "el" "tex" "y" "ye" "yr" "" )
+ if ( "${myext}" == "${xx}" ) then
+ set knownext = 1
+ break
+ endif
+ end
+ if ( $knownext == 0 ) then
+ echo For file ${file}:
+ grep '\$Log.*\$' "${name}"
+ echo -n "Please insert a comment leader for file ${name} > "
+ set comment = $<
+ endif
+ endif
+ 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 ( "${comment}" != "" ) then
+ $rcsbin/rcs -q -i -c"${comment}" -t${message_file} -m'.' "$file"
+ endif
+ $rcsbin/ci -q -u0.1 -t${message_file} -m'.' "$file"
+ if ( $status ) then
+ echo "ERROR: Initial check-in of $file failed - aborting"
+ exit 1
+ endif
+ set new = 1
+ endif
+ else
+ set file = "${update_dir}/Attic/${name},v"
+ echo "WARNING: IGNORED: ${repository}/Attic/${name}"
+ continue
+ endif
+ else # File existed
+ echo ERROR: File exists: Ignored: "$file"
+ continue
+# set headbranch = `sed -n '/^head/p; /^branch/p; 2q' $file`
+# if ( $#headbranch != 2 && $#headbranch != 4 ) then
+# echo "ERROR: corrupted RCS file $file - aborting"
+# endif
+# set head = "$headbranch[2]"
+# set branch = ""
+# if ( $#headbranch == 4 ) then
+# set branch = "$headbranch[4]"
+# endif
+# if ( "$head" == "1.1;" && "$branch" != "1.1.1;" ) then
+# ${rcsbin}/rcsdiff -q -r1.1 $file > /dev/null
+# if ( ! $status ) then
+# set new = 1
+# endif
+# else
+# if ( "$branch" != "1.1.1;" ) then
+# echo -n "WARNING: Updating locally modified file "
+# echo "${repository}/${name}"
+# endif
+# endif
+ endif
+ endif
+end
+if ( $got_one == 1 ) rm $message_file
diff --git a/gnu/usr.bin/cvs/contrib/rcslock.pl b/gnu/usr.bin/cvs/contrib/rcslock.pl
new file mode 100644
index 0000000..db09b4b
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/rcslock.pl
@@ -0,0 +1,234 @@
+#!/usr/bin/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 b/gnu/usr.bin/cvs/contrib/sccs2rcs
new file mode 100644
index 0000000..a208645
--- /dev/null
+++ b/gnu/usr.bin/cvs/contrib/sccs2rcs
@@ -0,0 +1,277 @@
+#!/bin/csh -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.
+#
+# sccs2rcs,v 1.1 1992/04/10 03:04:26 berliner 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/Makefile b/gnu/usr.bin/cvs/cvs/Makefile
new file mode 100644
index 0000000..6af8b81
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/Makefile
@@ -0,0 +1,36 @@
+.if !defined(FREEBSD_DEVELOPER)
+PROG = cvs
+.else
+PROG = ncvs
+.endif
+
+CFLAGS += -I${.CURDIR}/../lib \
+ -DDIRENT -DSTDC_HEADERS -DPOSIX -DBROKEN_SIGISMEMBER \
+ -DFTIME_MISSING -DHAVE_TIMEZONE -DUTIME_NULL_MISSING
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD= -L${.CURDIR}/../lib/obj -lcvs
+.else
+LDADD= -L${.CURDIR}/../lib/ -lcvs
+.endif
+
+.if defined(FREEBSD_DEVELOPER)
+CFLAGS+= -DFREEBSD_DEVELOPER
+BINGRP= ncvs
+#BINMODE=2555
+.endif
+
+SRCS = add.c admin.c checkin.c checkout.c classify.c commit.c \
+create_adm.c diff.c entries.c find_names.c history.c ignore.c \
+import.c lock.c log.c logmsg.c main.c rcs.c modules.c \
+no_diff.c parseinfo.c patch.c recurse.c release.c remove.c repos.c rtag.c \
+status.c tag.c update.c vers_ts.c version.c
+
+MAN1= cvs.1
+MAN5= cvs.5
+
+check:
+ @echo `pwd` ${.CURDIR}
+
+.include <bsd.prog.mk>
+.include "../../Makefile.inc"
diff --git a/gnu/usr.bin/cvs/cvs/add.c b/gnu/usr.bin/cvs/cvs/add.c
new file mode 100644
index 0000000..b4925bf
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/add.c
@@ -0,0 +1,447 @@
+/*
+ * 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.3 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"
+
+#ifndef lint
+static char rcsid[] = "@(#)add.c 1.46 92/04/03";
+#endif
+
+#if __STDC__
+static int add_directory (char *repository, char *dir);
+static int build_entry (char *repository, char *user, char *options,
+ char *message, List * entries);
+#else
+static int add_directory ();
+static int build_entry ();
+#endif /* __STDC__ */
+
+static char *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[MAXMESGLEN];
+ 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);
+
+ /* parse args */
+ message[0] = '\0';
+ optind = 1;
+ while ((c = gnu_getopt (argc, argv, "k:m:")) != -1)
+ {
+ switch (c)
+ {
+ case 'k':
+ if (options)
+ free (options);
+ options = RCS_check_kflag (optarg);
+ break;
+
+ case 'm':
+ if (strlen (optarg) >= sizeof (message))
+ {
+ error (0, 0, "warning: message too long; truncated!");
+ (void) strncpy (message, optarg, sizeof (message));
+ message[sizeof (message) - 1] = '\0';
+ }
+ else
+ (void) strcpy (message, 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);
+ entries = ParseEntries (0);
+
+ /* walk the arg list adding files/dirs */
+ for (i = 0; i < argc; i++)
+ {
+ int begin_err = err;
+
+ user = argv[i];
+ if (index (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))
+ {
+ /*
+ * 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) != 0)
+ err++;
+ else if (!quiet)
+ {
+ added_files++;
+ error (0, 0, "scheduling file `%s' for addition",
+ user);
+ }
+ }
+ }
+ 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);
+ free (tmp);
+
+ /* XXX - bugs here; this really resurrect the head */
+ 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))
+ {
+ err += add_directory (repository, user);
+ continue;
+ }
+ }
+ if (added_files)
+ error (0, 0, "use 'cvs commit' to add %s permanently",
+ (added_files == 1) ? "this file" : "these files");
+ dellist (&entries);
+ 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 cwd[PATH_MAX], rcsdir[PATH_MAX];
+ char message[PATH_MAX + 100];
+ char *tag, *date;
+
+ if (index (dir, '/') != NULL)
+ {
+ error (0, 0,
+ "directory %s not added; must be a direct sub-directory", dir);
+ return (1);
+ }
+ if (strcmp (dir, CVSADM) == 0 || strcmp (dir, OCVSADM) == 0)
+ {
+ error (0, 0, "cannot add a `%s' or a `%s' directory", CVSADM, OCVSADM);
+ 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 (getwd (cwd) == NULL)
+ {
+ error (0, 0, "cannot get working directory: %s", cwd);
+ return (1);
+ }
+ if (chdir (dir) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", dir);
+ return (1);
+ }
+ if (isfile (CVSADM) || isfile (OCVSADM))
+ {
+ error (0, 0,
+ "%s/%s (or %s/%s) already exists", dir, CVSADM, dir, OCVSADM);
+ 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;
+ char line[MAXLINELEN];
+ Node *p;
+ List *ulist;
+
+ (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;
+ }
+ omask = umask (2);
+ if (mkdir (rcsdir, 0777) < 0)
+ {
+ error (0, errno, "cannot mkdir %s", rcsdir);
+ (void) umask ((int) omask);
+ goto out;
+ }
+ (void) umask ((int) 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);
+ }
+
+ Create_Admin (".", rcsdir, tag, date);
+ if (tag)
+ free (tag);
+ if (date)
+ free (date);
+
+ (void) printf ("%s", message);
+out:
+ if (chdir (cwd) < 0)
+ error (1, errno, "cannot chdir to %s", 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)
+ char *repository;
+ char *user;
+ char *options;
+ char *message;
+ List *entries;
+{
+ char fname[PATH_MAX];
+ char line[MAXLINELEN];
+ FILE *fp;
+
+ /*
+ * 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);
+ }
+
+ if (noexec)
+ return (0);
+
+ /*
+ * The options for the "add" command are store in the file CVS/user,p
+ */
+ (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_OPT);
+ fp = open_file (fname, "w+");
+ if (fclose (fp) == EOF)
+ error(1, errno, "cannot close %s", fname);
+
+ /*
+ * And 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 ,p
+ * and ,t files, but who cares).
+ */
+ (void) sprintf (line, "Initial %s", user);
+ Register (entries, user, "0", line, options, (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..91d3929
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/admin.c
@@ -0,0 +1,124 @@
+/*
+ * 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.3 kit.
+ *
+ * Administration
+ *
+ * For now, this is basically a front end for rcs. All options are passed
+ * directly on.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static char rcsid[] = "@(#)admin.c 1.17 92/03/31";
+#endif
+
+#if __STDC__
+static Dtype admin_dirproc (char *dir, char *repos, char *update_dir);
+static int admin_fileproc (char *file, char *update_dir,
+ char *repository, List *entries,
+ List *srcfiles);
+#else
+static int admin_fileproc ();
+static Dtype admin_dirproc ();
+#endif /* __STDC__ */
+
+static char *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;
+
+ if (argc <= 1)
+ usage (admin_usage);
+
+ /* 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);
+
+ /* start the recursion processor */
+ err = start_recursion (admin_fileproc, (int (*) ()) NULL, admin_dirproc,
+ (int (*) ()) NULL, argc, argv, 0,
+ W_LOCAL, 0, 1, (char *) NULL, 1);
+ 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..44b733e
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/checkin.c
@@ -0,0 +1,142 @@
+/*
+ * 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.3 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 char rcsid[] = "@(#)checkin.c 1.40 92/03/31";
+#endif
+
+int
+Checkin (type, file, repository, rcs, rev, tag, message, entries)
+ int type;
+ char *file;
+ char *repository;
+ char *rcs;
+ char *rev;
+ char *tag;
+ char *message;
+ List *entries;
+{
+ char fname[PATH_MAX];
+ Vers_TS *vers;
+
+ (void) printf ("Checking in %s;\n", file);
+ (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.
+ */
+ if (!noexec)
+ copy_file (file, fname);
+
+ run_setup ("%s%s -f %s%s", Rcsbin, RCS_CI,
+ rev ? "-r" : "", rev ? rev : "");
+ run_args ("-m%s", 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.
+ */
+
+ /* XXX - make sure -k options are used on the co; and tag/date? */
+#ifdef FREEBSD_DEVELOPER
+ run_setup ("%s%s -q %s%s %s", Rcsbin, RCS_CO,
+ rev ? "-r" : "", rev ? rev : "",
+ freebsd ? "-KeAuthor,Date,Header,Id,Locker,Log,"
+ "RCSfile,Revision,Source,State -KiFreeBSD" : "");
+#else
+ run_setup ("%s%s -q %s%s", Rcsbin, RCS_CO,
+ rev ? "-r" : "", rev ? rev : "");
+#endif /* FREEBSD_DEVELOPER */
+ 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);
+ else
+ (void) unlink_file (fname);
+
+ /*
+ * If we want read-only files, muck the permissions here, before
+ * getting the file time-stamp.
+ */
+ if (cvswrite == FALSE)
+ xchmod (file, 0);
+
+ /* for added files with symbolic tags, need to add the tag too */
+ if (type == 'A' && tag && !isdigit (*tag))
+ {
+ run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, tag, rev);
+ run_arg (rcs);
+ (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ }
+
+ /* re-register with the new data */
+ vers = Version_TS (repository, (char *) NULL, tag, (char *) NULL,
+ file, 1, 1, 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);
+ history_write (type, (char *) 0, vers->vn_rcs, file, repository);
+ freevers_ts (&vers);
+ break;
+
+ case -1: /* fork failed */
+ if (!noexec)
+ error (1, errno, "could not check in %s -- fork failed", file);
+ 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 (!noexec)
+ {
+ rename_file (fname, file);
+ error (0, 0, "could not check in %s", file);
+ }
+ 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)
+ {
+ run_setup ("%s%s -q -u", Rcsbin, RCS);
+ run_arg (rcs);
+ (void) run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL);
+ }
+ 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..e7bc608
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/checkout.c
@@ -0,0 +1,730 @@
+/*
+ * 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.3 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 char rcsid[] = "@(#)checkout.c 1.67 92/04/10";
+#endif
+
+#if __STDC__
+static char *findslash (char *start, char *p);
+static int build_dirs_and_chdir (char *dir, char *prepath, char *realdir,
+ int sticky);
+static int checkout_proc (int *pargc, char *argv[], char *where,
+ char *mwhere, char *mfile, int shorten,
+ int local_specified, char *omodule,
+ char *msg);
+#else
+static int checkout_proc ();
+static char *findslash ();
+static int build_dirs_and_chdir ();
+#endif /* __STDC__ */
+
+static char *checkout_usage[] =
+{
+ "Usage:\n %s %s [-ANPQcflnpqs] [-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-Q\tReally quiet.\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-q\tSomewhat quiet.\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 key\tUse RCS key -K option on checkout.\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 char *export_usage[] =
+{
+ "Usage: %s %s [-NPQflnq] [-r rev | -D date] [-d dir] module...\n",
+ "\t-N\tDon't shorten module paths if -d specified.\n",
+ "\t-Q\tReally quiet.\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-q\tSomewhat quiet.\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",
+ 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;
+static char *K_flag = NULL;
+
+int
+checkout (argc, argv)
+ int argc;
+ char *argv[];
+{
+ register 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, **valid_usage;
+
+ /*
+ * 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 on (like -kv) and takes care to remove the CVS directory
+ * when it has done its duty
+ */
+ if (strcmp (command_name, "export") == 0)
+ {
+ valid_options = "Nnd:flRQqr:D:";
+ valid_usage = export_usage;
+ }
+ else
+ {
+ valid_options = "ANnk:d:flRpQqcsr:D:j:PK:";
+ valid_usage = checkout_usage;
+ }
+
+ if (argc == -1)
+ usage (valid_usage);
+
+ ign_setup ();
+
+ optind = 1;
+ while ((c = gnu_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':
+ really_quiet = 1;
+ /* FALL THROUGH */
+ case 'q':
+ quiet = 1;
+ 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 'K':
+ K_flag = optarg;
+ break;
+ case '?':
+ default:
+ usage (valid_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef FREEBSD_DEVELOPER
+ if (!K_flag && freebsd) {
+ /* XXX Note: The leading -K is not needed, it gets added later! */
+ K_flag = "eAuthor,Date,Header,Id,Locker,Log,RCSfile,Revision,Source,State -KiFreeBSD";
+ }
+#endif /* FREEBSD_DEVELOPER */
+ 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);
+ options = RCS_check_kflag ("v");/* -kv must be on */
+ }
+
+ 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) 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) && !isfile (OCVSADM))
+ {
+ (void) sprintf (repository, "%s/%s", CVSroot, CVSNULLREPOS);
+ if (!isfile (repository))
+ (void) mkdir (repository, 0777);
+ Create_Admin (".", 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);
+ }
+ }
+ }
+
+ /*
+ * 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 && index (where, '/') != NULL)
+ {
+ char *slash;
+
+ slash = rindex (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], CHECKOUT, "Updating", checkout_proc,
+ where, shorten, local, run_module_prog,
+ (char *) NULL);
+ close_module (db);
+ return (err);
+}
+
+/*
+ * 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 = rindex (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 = rindex (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 = rindex (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 = rindex (where, '/');
+ cp2 = rindex (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) && !isfile (OCVSADM))
+ {
+ FILE *fp;
+
+ if (!noexec && *pargc > 1)
+ {
+ Create_Admin (".", repository, (char *) NULL, (char *) NULL);
+ fp = open_file (CVSADM_ENTSTAT, "w+");
+ if (fclose(fp) == EOF)
+ error(1, errno, "cannot close %s", CVSADM_ENTSTAT);
+ }
+ else
+ Create_Admin (".", repository, tag, date);
+ }
+ else
+ {
+ char *repos;
+
+ /* get the contents of the previously existing repository */
+ repos = Name_Repository ((char *) NULL, preload_update_dir);
+ if (strcmp (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,
+ K_flag,
+ 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 = ParseEntries (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, line, vers->options,
+ vers->tag, vers->date);
+ }
+ freevers_ts (&vers);
+ }
+ dellist (&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, K_flag, preload_update_dir);
+ free (preload_update_dir);
+ preload_update_dir = oldupdate;
+ return (err);
+}
+
+static char *
+findslash (start, p)
+ char *start;
+ char *p;
+{
+ while ((int) p >= (int) start && *p != '/')
+ p--;
+ if ((int) p < (int) 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 = index (cp, '/')) != NULL && (slash2 = index (cp2, '/')) != NULL;
+ cp = slash + 1, cp2 = slash2 + 1)
+ {
+ *slash = '\0';
+ *slash2 = '\0';
+ (void) mkdir (cp, 0777);
+ if (chdir (cp) < 0)
+ {
+ error (0, errno, "cannot chdir to %s", cp);
+ return (1);
+ }
+ if (!isfile (CVSADM) && !isfile (OCVSADM) &&
+ strcmp (command_name, "export") != 0)
+ {
+ (void) sprintf (repository, "%s/%s", prepath, path2);
+ Create_Admin (".", 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);
+ }
+ }
+ *slash = '/';
+ *slash2 = '/';
+ }
+ (void) 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..318fab8
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/classify.c
@@ -0,0 +1,380 @@
+/*
+ * 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.3 kit.
+ *
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static char rcsid[] = "@(#)classify.c 1.11 92/03/31";
+#endif
+
+#if __STDC__
+static void sticky_ck (char *file, int aflag, Vers_TS * vers, List * entries);
+#else
+static void sticky_ck ();
+#endif /* __STDC__ */
+
+/*
+ * Classify the state of a file
+ */
+Ctype
+Classify_File (file, tag, date, options, force_tag_match, aflag, repository,
+ entries, srcfiles, versp)
+ char *file;
+ char *tag;
+ char *date;
+ char *options;
+ int force_tag_match;
+ int aflag;
+ char *repository;
+ List *entries;
+ List *srcfiles;
+ Vers_TS **versp;
+{
+ Vers_TS *vers;
+ Ctype ret;
+
+ /* 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", file);
+ 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",
+ file);
+ ret = T_UNKNOWN;
+ }
+ }
+ else
+ {
+ /* there is an rcs file */
+
+ if (vers->ts_user == NULL)
+ {
+ /* There is no user file; needs checkout */
+ ret = T_CHECKOUT;
+ }
+ else
+ {
+ /*
+ * 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
+ */
+ if (No_Difference (file, vers, entries))
+ {
+ /* the files were different so it is a conflict */
+ if (!really_quiet)
+ error (0, 0, "move away %s; it is in the way", file);
+ 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", file);
+ 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;
+ else
+ {
+ /*
+ * 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",
+ file);
+ 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",
+ file);
+ 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", file);
+ 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",
+ file);
+ 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", file);
+ 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))
+ {
+ /* they are different -> conflict */
+ if (!really_quiet)
+ error (0, 0,
+ "conflict: %s is modified but no longer in the repository",
+ file);
+ ret = T_CONFLICT;
+ }
+ else
+ {
+ /* they weren't really different */
+ if (!really_quiet)
+ error (0, 0,
+ "warning: %s is not (any longer) pertinent",
+ file);
+ 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", file);
+ 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
+ {
+ sticky_ck (file, aflag, vers, entries);
+ 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))
+ {
+
+ /*
+ * 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;
+ sticky_ck (file, aflag, vers, entries);
+#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", file);
+ 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
+ */
+ ret = T_CHECKOUT;
+ }
+ else
+ {
+ if (No_Difference (file, vers, entries))
+ /* really modified, needs to merge */
+ ret = T_NEEDS_MERGE;
+ else
+ /* not really modified, check it out */
+ ret = T_CHECKOUT;
+ }
+ }
+ }
+
+ /* free up the vers struct, or just return it */
+ if (versp != (Vers_TS **) NULL)
+ *versp = vers;
+ else
+ freevers_ts (&vers);
+
+ /* return the status of the file */
+ return (ret);
+}
+
+static void
+sticky_ck (file, aflag, vers, entries)
+ char *file;
+ int aflag;
+ Vers_TS *vers;
+ List *entries;
+{
+ 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);
+ }
+ }
+}
diff --git a/gnu/usr.bin/cvs/cvs/commit.c b/gnu/usr.bin/cvs/cvs/commit.c
new file mode 100644
index 0000000..1b2f3be
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/commit.c
@@ -0,0 +1,1229 @@
+/*
+ * 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.3 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"
+
+#ifndef lint
+static char rcsid[] = "@(#)commit.c 1.84 92/03/31";
+#endif
+
+#if __STDC__
+static Dtype check_direntproc (char *dir, char *repos, char *update_dir);
+static int check_fileproc (char *file, char *update_dir, char *repository,
+ List * entries, List * srcfiles);
+static int check_filesdoneproc (int err, char *repos, char *update_dir);
+static int checkaddfile (char *file, char *repository, char *tag);
+static Dtype commit_direntproc (char *dir, char *repos, char *update_dir);
+static int commit_dirleaveproc (char *dir, int err, char *update_dir);
+static int commit_fileproc (char *file, char *update_dir, char *repository,
+ List * entries, List * srcfiles);
+static int commit_filesdoneproc (int err, char *repository, char *update_dir);
+static int finaladd (char *file, char *revision, char *tag, char *repository,
+ List *entries);
+static int findmaxrev (Node * p);
+static int fsortcmp (Node * p, Node * q);
+static int lock_RCS (char *user, char *rcs, char *rev, char *repository);
+static int lock_filesdoneproc (int err, char *repository, char *update_dir);
+static int lockrcsfile (char *file, char *repository, char *rev);
+static int precommit_list_proc (Node * p);
+static int precommit_proc (char *repository, char *filter);
+static int remove_file (char *file, char *repository, char *tag,
+ List *entries);
+static void fix_rcs_modes (char *rcs, char *user);
+static void fixaddfile (char *file, char *repository);
+static void fixbranch (char *file, char *repository, char *branch);
+static void unlockrcs (char *file, char *repository);
+static void ci_delproc (Node *p);
+static void locate_rcs (char *file, char *repository, char *rcs);
+#else
+static int fsortcmp ();
+static int lock_filesdoneproc ();
+static int check_fileproc ();
+static Dtype check_direntproc ();
+static int precommit_list_proc ();
+static int precommit_proc ();
+static int check_filesdoneproc ();
+static int commit_fileproc ();
+static int commit_filesdoneproc ();
+static Dtype commit_direntproc ();
+static int commit_dirleaveproc ();
+static int findmaxrev ();
+static int remove_file ();
+static int finaladd ();
+static void unlockrcs ();
+static void fixaddfile ();
+static void fixbranch ();
+static int checkaddfile ();
+static int lockrcsfile ();
+static int lock_RCS ();
+static void fix_rcs_modes ();
+static void ci_delproc ();
+static void locate_rcs ();
+#endif /* __STDC__ */
+
+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 */
+};
+struct master_lists
+{
+ List *ulist; /* list for Update_Logfile */
+ List *cilist; /* list with commit_info structs */
+};
+
+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 char *commit_usage[] =
+{
+ "Usage: %s %s [-nRl] [-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 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 */
+
+ message = xmalloc (MAXMESGLEN + 1);
+ message[0] = '\0'; /* Null message by default */
+ optind = 1;
+ while ((c = gnu_getopt (argc, argv, "nlRm:f: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 (strlen (optarg) >= (size_t) MAXMESGLEN)
+ {
+ error (0, 0, "warning: message too long; truncated!");
+ (void) strncpy (message, optarg, MAXMESGLEN);
+ message[MAXMESGLEN] = '\0';
+ }
+ else
+ (void) strcpy (message, optarg);
+ break;
+ case 'r':
+ if (tag)
+ free (tag);
+ tag = xstrdup (optarg);
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ 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;
+
+ if (*message)
+ error (1, 0, "cannot specify both a message and a log file");
+
+ if ((logfd = open (logfile, O_RDONLY)) < 0 ||
+ (n = read (logfd, message, MAXMESGLEN)) < 0)
+ {
+ error (1, errno, "cannot read log message from %s", logfile);
+ }
+ (void) close (logfd);
+ message[n] = '\0';
+ }
+
+ /* XXX - this is not the perfect check for this */
+ if (argc <= 0)
+ write_dirtag = tag;
+
+ /*
+ * Run the recursion processor to find all the dirs to lock and lock all
+ * the dirs
+ */
+ locklist = getlist ();
+ err = start_recursion ((int (*) ()) NULL, lock_filesdoneproc,
+ (Dtype (*) ()) NULL, (int (*) ()) NULL, argc,
+ argv, local, W_LOCAL, aflag, 0, (char *) NULL, 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, (int (*) ()) NULL, argc,
+ argv, local, W_LOCAL, aflag, 0, (char *) NULL, 1);
+ 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);
+
+ /*
+ * 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)
+ Node *p, *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);
+ 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);
+ if (status == T_UPTODATE)
+ {
+ freevers_ts (&vers);
+ status = Classify_File (file, tag, (char *) NULL,
+ (char *) NULL, 1, aflag, repository,
+ entries, srcfiles, &vers);
+ if (status == T_REMOVE_ENTRY)
+ status = T_MODIFIED;
+ }
+ }
+ 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 = rindex (xtag, '.');
+ *cp = '\0';
+ }
+ status = Classify_File (file, xtag, (char *) NULL,
+ (char *) NULL, 1, aflag, repository,
+ entries, srcfiles, &vers);
+ if ((status == T_REMOVE_ENTRY || status == T_CONFLICT)
+ && (cp = rindex (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);
+ 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);
+ noexec = save_noexec;
+ quiet = save_quiet;
+ really_quiet = save_really_quiet;
+
+ switch (status)
+ {
+ case T_CHECKOUT:
+ case T_NEEDS_MERGE:
+ case T_CONFLICT:
+ case T_REMOVE_ENTRY:
+ error (0, 0, "Up-to-date check failed for `%s'", 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 (!tag || !isdigit (*tag))
+ {
+ if (vers->date)
+ {
+ error (0, 0,
+ "cannot commit with sticky date for file `%s'",
+ file);
+ freevers_ts (&vers);
+ return (1);
+ }
+ if (status == T_MODIFIED && vers->tag &&
+ !RCS_isbranch (file, vers->tag, srcfiles))
+ {
+ error (0, 0,
+ "sticky tag `%s' for file `%s' is not a branch",
+ vers->tag, file);
+ freevers_ts (&vers);
+ return (1);
+ }
+ }
+ if (status == T_REMOVED && vers->tag && isdigit (*vers->tag))
+ {
+ error (0, 0,
+ "cannot remove file `%s' which has a numeric sticky tag of `%s'",
+ file, vers->tag);
+ freevers_ts (&vers);
+ return (1);
+ }
+ if (status == T_ADDED)
+ {
+ char rcs[PATH_MAX];
+
+ locate_rcs (file, repository, rcs);
+ if (isreadable (rcs))
+ {
+ error (0, 0,
+ "cannot add file `%s' when RCS file `%s' already exists",
+ file, rcs);
+ freevers_ts (&vers);
+ return (1);
+ }
+ if (vers->tag && isdigit (*vers->tag) &&
+ numdots (vers->tag) > 1)
+ {
+ error (0, 0,
+ "cannot add file `%s' with revision `%s'; must be on trunk",
+ 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;
+ (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);
+ p->data = (char *) ci;
+ (void) addnode (cilist, p);
+ break;
+ case T_UNKNOWN:
+ error (0, 0, "nothing known about `%s'", file);
+ freevers_ts (&vers);
+ return (1);
+ case T_UPTODATE:
+ break;
+ default:
+ error (0, 0, "Unknown status 0x%x for `%s'", status, file);
+ 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)
+ Node *p;
+{
+ if (p->data == (char *) T_ADDED || p->data == (char *) T_MODIFIED)
+ 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 (filter[0] == '/' && !isfile (filter))
+ {
+ error (0, errno, "cannot find pre-commit filter `%s'", filter);
+ return (1); /* so it fails! */
+ }
+
+ run_setup ("%s %s", filter, repository);
+ (void) walklist (ulist, precommit_list_proc);
+ 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);
+ return (1);
+ }
+ }
+ else if (ci->status == T_ADDED)
+ {
+ if (checkaddfile (file, repository, ci->tag) != 0)
+ {
+ fixaddfile (file, repository);
+ return (1);
+ }
+ }
+
+ /*
+ * 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);
+ 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,
+ repository, entries);
+ if (xrev)
+ free (xrev);
+ return (err);
+ }
+
+ if (ci->status == T_MODIFIED)
+ {
+ locate_rcs (file, repository, rcs);
+ err = Checkin ('M', file, repository, rcs, ci->rev, ci->tag,
+ message, entries);
+ if (err != 0)
+ {
+ unlockrcs (file, repository);
+ fixbranch (file, repository, sbranch);
+ }
+ }
+
+ if (ci->status == T_REMOVED)
+ err = remove_file (file, repository, ci->tag, entries);
+
+ 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;
+{
+ List *ulist, *cilist;
+ char *xtag = (char *) NULL;
+ Node *p;
+
+ p = findnode (mulist, update_dir);
+ if (p != NULL)
+ {
+ ulist = ((struct master_lists *) p->data)->ulist;
+ cilist = ((struct master_lists *) p->data)->cilist;
+ }
+ else
+ return (err);
+
+ 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);
+ dellist (&ulist);
+ dellist (&cilist);
+ if (xtag)
+ free (xtag);
+
+ if (err == 0 && run_module_prog)
+ {
+ char *cp;
+ FILE *fp;
+ char line[MAXLINELEN];
+ char *repository;
+
+ /* It is not an error if Checkin.prog does not exist. */
+ if ((fp = fopen (CVSADM_CIPROG, "r")) != NULL)
+ {
+ if (fgets (line, sizeof (line), fp) != NULL)
+ {
+ if ((cp = rindex (line, '\n')) != NULL)
+ *cp = '\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);
+ }
+ (void) fclose (fp);
+ }
+ }
+
+ 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);
+
+ return (err);
+}
+
+/*
+ * find the maximum major rev number in an entries file
+ */
+static int
+findmaxrev (p)
+ Node *p;
+{
+ char *cp;
+ int thisrev;
+ Entnode *entdata;
+
+ entdata = (Entnode *) p->data;
+ cp = index (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, entries)
+ char *file;
+ char *repository;
+ char *tag;
+ List *entries;
+{
+ int omask;
+ int retcode;
+ char rcs[PATH_MAX];
+ char tmp[PATH_MAX];
+
+ locate_rcs (file, repository, rcs);
+ if (tag)
+ {
+ /* a symbolic tag is specified; just remove the tag from the file */
+ run_setup ("%s%s -q -N%s", Rcsbin, RCS, tag);
+ 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 remove tag `%s' from `%s'", tag, rcs);
+ return (1);
+ }
+ return (0);
+ }
+ else
+ {
+ /* no symbolic tag specified; really move it into the Attic */
+ (void) sprintf (tmp, "%s/%s", repository, CVSATTIC);
+ omask = umask (2);
+ (void) mkdir (tmp, 0777);
+ (void) umask (omask);
+ (void) sprintf (tmp, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
+
+ if ((strcmp (rcs, tmp) == 0 || rename (rcs, tmp) != -1) ||
+ (!isreadable (rcs) && isreadable (tmp)))
+ {
+ Scratch_Entry (entries, file);
+ return (0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Do the actual checkin for added files
+ */
+static int
+finaladd (file, rev, tag, repository, entries)
+ char *file;
+ char *rev;
+ char *tag;
+ char *repository;
+ List *entries;
+{
+ int ret;
+ char tmp[PATH_MAX];
+ char rcs[PATH_MAX];
+
+ locate_rcs (file, repository, rcs);
+ ret = Checkin ('A', file, repository, rcs, rev, tag,
+ message, entries);
+ if (ret == 0)
+ {
+ (void) sprintf (tmp, "%s/%s%s", CVSADM, file, CVSEXT_OPT);
+ (void) unlink_file (tmp);
+ (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);
+ run_setup ("%s%s -q -u", Rcsbin, RCS);
+ 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 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);
+ run_setup ("%s%s -q -b%s", Rcsbin, RCS, branch);
+ 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,
+ "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)
+ char *file;
+ char *repository;
+ char *tag;
+{
+ FILE *fp;
+ char *cp;
+ char rcs[PATH_MAX];
+ char fname[PATH_MAX];
+ int omask;
+ int retcode = 0;
+
+ if (tag)
+ {
+ (void) sprintf(rcs, "%s/%s", repository, CVSATTIC);
+ omask = umask (2);
+ (void) mkdir (rcs, 0777);
+ (void) umask (omask);
+ (void) sprintf (rcs, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
+ }
+ else
+ locate_rcs (file, repository, rcs);
+
+ run_setup ("%s%s -i", Rcsbin, RCS);
+ run_args ("-t%s/%s%s", CVSADM, file, CVSEXT_LOG);
+ (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_OPT);
+ fp = open_file (fname, "r");
+ while (fgets (fname, sizeof (fname), fp) != NULL)
+ {
+ if ((cp = rindex (fname, '\n')) != NULL)
+ *cp = '\0';
+ if (*fname)
+ run_arg (fname);
+ }
+ (void) fclose (fp);
+ 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);
+ }
+ 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)
+ {
+ run_setup ("%s%s -q -b", Rcsbin, RCS);
+ run_arg (rcs);
+ if (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0)
+ {
+ error (0, 0, "cannot change branch to default for %s",
+ rcs);
+ if (branch)
+ free (branch);
+ return (1);
+ }
+ }
+ run_setup ("%s%s -q -l", Rcsbin, RCS);
+ run_arg (rcs);
+ err = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ }
+ }
+ else
+ {
+ run_setup ("%s%s -q -l%s", Rcsbin, RCS, rev ? rev : "");
+ run_arg (rcs);
+ (void) run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL);
+ }
+
+ 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);
+ free (ci);
+}
+
+/*
+ * 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/config.h b/gnu/usr.bin/cvs/cvs/config.h
new file mode 100644
index 0000000..b3bee5f
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/config.h
@@ -0,0 +1,217 @@
+/* @(#)config.h 1.19 92/03/31 */
+
+/*
+ * 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.3 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. 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 "diff"
+#endif
+
+/*
+ * The "grep" program to execute when checking to see if a merged file had
+ * any conflicts. This "grep" must support the "-s" option and a standard
+ * 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
+
+/*
+ * 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 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 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
+
+/* 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
+
+/*
+ * 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
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..911258e
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/create_adm.c
@@ -0,0 +1,100 @@
+/*
+ * 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.3 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 char rcsid[] = "@(#)create_adm.c 1.24 92/03/31";
+#endif
+
+void
+Create_Admin (dir, repository, tag, date)
+ char *dir;
+ char *repository;
+ char *tag;
+ char *date;
+{
+ FILE *fout;
+ char *cp;
+ char tmp[PATH_MAX];
+
+ if (noexec)
+ return;
+
+ if (!isdir (repository))
+ error (1, 0, "there is no repository %s", repository);
+
+ 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 here already");
+ else
+ {
+ if (dir != NULL)
+ (void) sprintf (tmp, "%s/%s", dir, OCVSADM);
+ else
+ (void) strcpy (tmp, OCVSADM);
+
+ if (isfile (tmp))
+ error (1, 0, "there is a version here already");
+ }
+
+ if (dir != NULL)
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM);
+ else
+ (void) strcpy (tmp, CVSADM);
+ make_directory (tmp);
+
+ if (dir != NULL)
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM_REP);
+ else
+ (void) strcpy (tmp, CVSADM_REP);
+ fout = open_file (tmp, "w+");
+ 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) == EOF)
+ error (1, errno, "write to %s failed", tmp);
+ if (fclose (fout) == EOF)
+ error (1, errno, "cannot close %s", tmp);
+
+ /* now, do the Entries file */
+ if (dir != NULL)
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENT);
+ else
+ (void) strcpy (tmp, CVSADM_ENT);
+ fout = open_file (tmp, "w+");
+ if (fclose (fout) == EOF)
+ error (1, errno, "cannot close %s", tmp);
+
+ /* Create a new CVS/Tag file */
+ WriteTag (dir, tag, date);
+}
diff --git a/gnu/usr.bin/cvs/cvs/cvs.1 b/gnu/usr.bin/cvs/cvs/cvs.1
new file mode 100644
index 0000000..f0c648f
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/cvs.1
@@ -0,0 +1,1991 @@
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id cvs.1,v 1.12 1992/04/10 03:05:16 berliner 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"
+elicits a list of available commands, and
+.` "cvs \-v "
+displays version information on \fBcvs\fP itself.
+.SP
+.SH "CVS OPTIONS"
+Use these options to control the overall
+.B cvs
+program:
+.TP
+.B \-H
+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 EDITOR
+environment variable.
+.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 files read-only.
+Same effect as if the
+.SM CVSREAD
+environment variable is set.
+.TP
+.B \-v
+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.
+.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 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. 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 rcs ( 1 )
+are available. The \fB\-k\fP option is available with the
+.BR add ", " checkout ", " diff ", "
+.RB 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.
+.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
+.B \-Q
+Causes the command to be
+.I really
+quiet; the command will generate output only for serious problems.
+Available with the following commands:
+.BR checkout ", " import ", " export ", "
+.BR rdiff ", " rtag ", "
+.BR tag ", and " update .
+.TP
+.B \-q
+Causes the command to be somewhat quiet; informational messages, such
+as reports of recursion through subdirectories, are suppressed.
+Available with the following commands:
+.BR checkout ", " import ", " export ", "
+.BR rtag ", "
+.BR tag ", and " update .
+.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
+option along with the
+.B \-r
+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
+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 ", " \-Q ", " \-f ", "
+.BI \-k " kflag"
+\&,
+.BR \-l ", " \-n ", " \-p ", "
+.BR \-q ", " \-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.
+.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] \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 always set 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.
+There is no way to override this.
+.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 \fItyp\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".
+.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 *.orig *.rej .del\-*
+*.a *.o *.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
+Three of the standard
+.B cvs
+command options are available: \fB\-Q\fP, \fB\-q\fP, and \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 two additional special options.
+.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, \fB\-l\fP, \fB\-Q\fP, and
+\fB\-q\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, scheduing 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
+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
+The standard options \fB\-Q\fP and \fB\-q\fP are also available with
+this command.
+.SP
+Use the
+.B \-a
+option to have
+.B rtag
+look in the
+.` "Attic"
+for removed files that contin 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\-lR\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\-b\fP] [\fB\-d\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, but the versions are supplied
+implicitly by the \fBcvs\fP records of your working files' history
+rather than applied explicitly.
+.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
+.B checkout
+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
+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
+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 *.orig *.rej .del\-*
+*.a *.o *.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, \fB\-Q\fP, \fB\-q\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 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/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/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 dueing a
+.` "cvs commit"
+operation.
+.TP
+CVSROOT/editinfo,v
+Records programs for editing/validating
+.` "cvs commit"
+log entries.
+.TP
+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 EDITOR
+Specifies the program to use for recording log messages during
+.BR commit .
+If not set, the default is
+.BR /usr/ucb/vi .
+.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/cvs/cvs.5 b/gnu/usr.bin/cvs/cvs/cvs.5
new file mode 100644
index 0000000..49ca562
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/cvs.5
@@ -0,0 +1,326 @@
+.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/modules,v
+.TP
+.B $CVSROOT/CVSROOT/commitinfo,v
+.TP
+.B $CVSROOT/CVSROOT/loginfo,v
+.TP
+.B $CVSROOT/CVSROOT/rcsinfo,v
+.TP
+.B $CVSROOT/CVSROOT/editinfo,v
+.TP
+.B $CVSROOT/CVSROOT/cvsignore,v
+.TP
+.B $CVSROOT/CVSROOT/history
+.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 `\|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 `\|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 ( 1 )
+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\-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 `\|commitinfo\|', the rest of the line is a command-line template to
+execute.
+The template can include 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 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..3e1f8f4
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/cvs.h
@@ -0,0 +1,442 @@
+/* @(#)cvs.h 1.72 92/03/31 */
+
+#include "system.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <signal.h>
+#include "hash.h"
+#include "rcs.h"
+#include "regex.h"
+#include "fnmatch.h"
+#include "getopt.h"
+#include "wait.h"
+#include "config.h"
+#ifdef MY_NDBM
+#include "myndbm.h"
+#else
+#include <ndbm.h>
+#endif /* !MY_NDBM */
+
+/* XXX - for now this is static */
+#undef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN+2
+#else
+#define PATH_MAX 1024+2
+#endif
+
+/* just in case this implementation does not define this */
+#ifndef L_tmpnam
+#define L_tmpnam 50
+#endif
+
+#if __STDC__
+#define CONST const
+#define PTR void *
+#else
+#define CONST
+#define PTR char *
+#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.3 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_ENTSTAT "CVS/Entries.Static"
+#define CVSADM_REP "CVS/Repository"
+#define CVSADM_CIPROG "CVS/Checkin.prog"
+#define CVSADM_UPROG "CVS/Update.prog"
+#define CVSADM_TAG "CVS/Tag"
+
+/*
+ * The following are obsolete and are maintained here only so that they can be
+ * cleaned up during the transition
+ */
+#define OCVSADM "CVS.adm" /* for CVS 1.2 and earlier */
+#define CVSADM_FILE "CVS/Files"
+#define CVSADM_MOD "CVS/Mod"
+
+/*
+ * 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_EDITINFO "editinfo"
+#define CVSROOTADM_HISTORY "history"
+#define CVSROOTADM_IGNORE "cvsignore"
+#define CVSNULLREPOS "Emptydir" /* an empty directory */
+
+/* support for the modules file (CVSROOTADM_MODULES) */
+#define CVSMODULE_OPTS "ad:i:lo:s:t:u:"/* options in modules file */
+#define CVSMODULE_SPEC '&' /* special delimiter */
+
+/*
+ * The following are obsolete and are maintained here only so that they can be
+ * cleaned up during the transition
+ */
+#define OCVSROOTADM "CVSROOT.adm" /* for CVS 1.2 and earlier */
+
+/* Other CVS file names */
+#define CVSATTIC "Attic"
+#define CVSLCK "#cvs.lock"
+#define CVSTFL "#cvs.tfl"
+#define CVSRFL "#cvs.rfl"
+#define CVSWFL "#cvs.wfl"
+#define CVSEXT_OPT ",p"
+#define CVSEXT_LOG ",t"
+#define CVSPREFIX ",,"
+#define CVSDOTIGNORE ".cvsignore"
+
+/* 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 */
+#define DEVNULL "/dev/null"
+
+#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 EDITOR_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 */
+
+/*
+ * 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 MAXMESGLEN 10000 /* max RCS log message size */
+#define MAXDATELEN 50 /* max length for a date */
+
+/* The type of request that is being done in do_module() */
+enum mtype
+{
+ CHECKOUT, TAG, PATCH
+};
+
+/*
+ * 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 */
+ 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 verion for the rcs file
+ * (tag version?) */
+ 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 *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 ParseEntries() and
+ * Version_TS().
+ */
+struct stickydirtag
+{
+ int aflag;
+ char *tag;
+ char *date;
+ char *options;
+};
+
+/* 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 */
+
+/* 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, *command_name;
+extern char *Rcsbin, *Editor, *CVSroot;
+extern char *CurDir;
+extern int really_quiet, quiet;
+extern int use_editor;
+extern int cvswrite;
+
+extern int trace; /* Show all commands */
+extern int noexec; /* Don't modify disk anywhere */
+extern int logoff; /* Don't write history entry */
+#ifdef FREEBSD_DEVELOPER
+extern int freebsd; /* Assume option defaults for FreBSD */
+#endif /* FREEBSD_DEVELOPER */
+
+/* Externs that are included directly in the CVS sources */
+#if __STDC__
+int Reader_Lock (char *xrepository);
+DBM *open_module (void);
+FILE *Fopen (char *name, char *mode);
+FILE *open_file (char *name, char *mode);
+List *Find_Dirs (char *repository, int which);
+List *ParseEntries (int aflag);
+char *Make_Date (char *rawdate);
+char *Name_Repository (char *dir, char *update_dir);
+char *Short_Repository (char *repository);
+char *getcaller (void);
+char *time_stamp (char *file);
+char *xmalloc (int bytes);
+char *xrealloc (char *ptr, int bytes);
+char *xstrdup (char *str);
+int No_Difference (char *file, Vers_TS * vers, List * entries);
+int Parse_Info (char *infofile, char *repository, int (*callproc) (), int all);
+int Reader_Lock (char *xrepository);
+int SIG_register (int sig, SIGTYPE (*fn) ());
+int Writer_Lock (List * list);
+int gethostname (char *name, int namelen);
+int ign_name (char *name);
+int isdir (char *file);
+int isfile (char *file);
+int islink (char *file);
+int isreadable (char *file);
+int iswritable (char *file);
+int link_file (char *from, char *to);
+int numdots (char *s);
+int run_exec (char *stin, char *stout, char *sterr, int flags);
+int unlink_file (char *f);
+int update (int argc, char *argv[]);
+int xcmp (char *file1, char *file2);
+int yesno (void);
+time_t get_date (char *date, struct timeb *now);
+void Create_Admin (char *dir, char *repository, char *tag, char *date);
+void Lock_Cleanup (void);
+void ParseTag (char **tagp, char **datep);
+void Scratch_Entry (List * list, char *fname);
+void WriteTag (char *dir, char *tag, char *date);
+void cat_module (int status);
+void check_entries (char *dir);
+void close_module (DBM * db);
+void copy_file (char *from, char *to);
+void error (int status, int errnum, char *message,...);
+void fperror (FILE * fp, int status, int errnum, char *message,...);
+void free_names (int *pargc, char *argv[]);
+void freevers_ts (Vers_TS ** versp);
+void ign_add (char *ign, int hold);
+void ign_add_file (char *file, int hold);
+void ign_setup (void);
+void line2argv (int *pargc, char *argv[], char *line);
+void make_directories (char *name);
+void make_directory (char *name);
+void rename_file (char *from, char *to);
+void run_arg (char *s);
+void run_args (char *fmt,...);
+void run_print (FILE * fp);
+void run_setup (char *fmt,...);
+void strip_path (char *path);
+void update_delproc (Node * p);
+void usage (char **cpp);
+void xchmod (char *fname, int writable);
+int Checkin (int type, char *file, char *repository, char *rcs, char *rev,
+ char *tag, char *message, List * entries);
+Ctype Classify_File (char *file, char *tag, char *date, char *options,
+ int force_tag_match, int aflag, char *repository,
+ List *entries, List *srcfiles, Vers_TS **versp);
+List *Find_Names (char *repository, int which, int aflag,
+ List ** optentries);
+void Register (List * list, char *fname, char *vn, char *ts,
+ char *options, char *tag, char *date);
+void Update_Logfile (char *repository, char *xmessage, char *xrevision,
+ FILE * xlogfp, List * xchanges);
+Vers_TS *Version_TS (char *repository, char *options, char *tag,
+ char *date, char *user, int force_tag_match,
+ int set_time, List * entries, List * xfiles);
+void do_editor (char *dir, char *message, char *repository,
+ List * changes);
+int do_module (DBM * db, char *mname, enum mtype m_type, char *msg,
+ int (*callback_proc) (), char *where, int shorten,
+ int local_specified, int run_module_prog, char *extra_arg);
+int do_recursion (int (*xfileproc) (), int (*xfilesdoneproc) (),
+ Dtype (*xdirentproc) (), int (*xdirleaveproc) (),
+ Dtype xflags, int xwhich, int xaflag, int xreadlock,
+ int xdosrcs);
+int do_update (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 *xK_flag, char *preload_update_dir);
+void history_write (int type, char *update_dir, char *revs, char *name,
+ char *repository);
+int start_recursion (int (*fileproc) (), int (*filesdoneproc) (),
+ Dtype (*direntproc) (), int (*dirleaveproc) (),
+ int argc, char *argv[], int local, int which,
+ int aflag, int readlock, char *update_preload,
+ int dosrcs);
+void SIG_beginCrSect ();
+void SIG_endCrSect ();
+#else /* !__STDC__ */
+DBM *open_module ();
+FILE *Fopen ();
+FILE *open_file ();
+List *Find_Dirs ();
+List *Find_Names ();
+List *ParseEntries ();
+Vers_TS *Version_TS ();
+char *Make_Date ();
+char *Name_Repository ();
+char *Short_Repository ();
+char *getcaller ();
+char *time_stamp ();
+char *xmalloc ();
+char *xrealloc ();
+char *xstrdup ();
+int Checkin ();
+Ctype Classify_File ();
+int No_Difference ();
+int Parse_Info ();
+int Reader_Lock ();
+int SIG_register ();
+int Writer_Lock ();
+int do_module ();
+int do_recursion ();
+int do_update ();
+int gethostname ();
+int ign_name ();
+int isdir ();
+int isfile ();
+int islink ();
+int isreadable ();
+int iswritable ();
+int link_file ();
+int numdots ();
+int run_exec ();
+int start_recursion ();
+int unlink_file ();
+int update ();
+int xcmp ();
+int yesno ();
+time_t get_date ();
+void Create_Admin ();
+void Lock_Cleanup ();
+void ParseTag ();
+void ParseTag ();
+void Register ();
+void Scratch_Entry ();
+void Update_Logfile ();
+void WriteTag ();
+void cat_module ();
+void check_entries ();
+void close_module ();
+void copy_file ();
+void do_editor ();
+void error ();
+void fperror ();
+void free_names ();
+void freevers_ts ();
+void history_write ();
+void ign_add ();
+void ign_add_file ();
+void ign_setup ();
+void line2argv ();
+void make_directories ();
+void make_directory ();
+void rename_file ();
+void run_arg ();
+void run_args ();
+void run_print ();
+void run_setup ();
+void strip_path ();
+void update_delproc ();
+void usage ();
+void xchmod ();
+void SIG_beginCrSect ();
+void SIG_endCrSect ();
+#endif /* __STDC__ */
diff --git a/gnu/usr.bin/cvs/cvs/diff.c b/gnu/usr.bin/cvs/cvs/diff.c
new file mode 100644
index 0000000..003c2e3
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/diff.c
@@ -0,0 +1,429 @@
+/*
+ * 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.3 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 char rcsid[] = "@(#)diff.c 1.52 92/04/10";
+#endif
+
+#if __STDC__
+static Dtype diff_dirproc (char *dir, char *pos_repos, char *update_dir);
+static int diff_filesdoneproc (int err, char *repos, char *update_dir);
+static int diff_dirleaveproc (char *dir, int err, char *update_dir);
+static int diff_file_nodiff (char *file, char *repository, List *entries,
+ List *srcfiles, Vers_TS *vers);
+static int diff_fileproc (char *file, char *update_dir, char *repository,
+ List * entries, List * srcfiles);
+static void diff_mark_errors (int err);
+#else
+static int diff_fileproc ();
+static Dtype diff_dirproc ();
+static int diff_filesdoneproc ();
+static int diff_dirleaveproc ();
+static int diff_file_nodiff ();
+static void diff_mark_errors ();
+#endif /* __STDC__ */
+
+static char *diff_rev1, *diff_rev2;
+static char *diff_date1, *diff_date2;
+static char *use_rev1, *use_rev2;
+static char *options;
+static char opts[PATH_MAX];
+static int diff_errors;
+
+static char *diff_usage[] =
+{
+ "Usage: %s %s [-l] [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-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;
+
+ 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.
+ */
+ optind = 1;
+ while ((c = gnu_getopt (argc, argv,
+ "abcdefhilnpqtuw0123456789BHQRTC: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 '?':
+ default:
+ usage (diff_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* make sure options is non-null */
+ if (!options)
+ options = xstrdup ("");
+
+ /* start the recursion processor */
+ err = start_recursion (diff_fileproc, diff_filesdoneproc, diff_dirproc,
+ diff_dirleaveproc, argc, argv, local,
+ W_LOCAL, 0, 1, (char *) NULL, 1);
+
+ /* 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;
+
+ vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
+ file, 1, 0, entries, srcfiles);
+
+ 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')
+ {
+ 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] == '-')
+ {
+ 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);
+ }
+ }
+ }
+
+ if (diff_file_nodiff (file, repository, entries, srcfiles, vers))
+ {
+ freevers_ts (&vers);
+ return (0);
+ }
+
+ /* 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);
+
+ 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;
+ }
+
+ (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
+ */
+/* 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??? */
+ 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)
+ {
+ 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)
+ {
+ 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 */
+ return (strcmp (use_rev1, use_rev2) == 0);
+ }
+ 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..6453e4f
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/entries.c
@@ -0,0 +1,488 @@
+/*
+ * 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.3 kit.
+ *
+ * Entries file to Files file
+ *
+ * Creates the file Files containing the names that comprise the project, from
+ * the Entries file.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static char rcsid[] = "@(#)entries.c 1.37 92/03/31";
+#endif
+
+#if __STDC__
+static Node *AddEntryNode (List * list, char *name, char *version,
+ char *timestamp, char *options, char *tag,
+ char *date);
+#else
+static Node *AddEntryNode ();
+#endif /* __STDC__ */
+
+static FILE *entfile;
+static char *entfilename; /* for error messages */
+
+/*
+ * Write out the line associated with a node of an entries file
+ */
+static int
+write_ent_proc (node)
+ Node *node;
+{
+ Entnode *p;
+
+ p = (Entnode *) node->data;
+ if (fprintf (entfile, "/%s/%s/%s/%s/", node->key, p->version,
+ p->timestamp, p->options) == EOF)
+ error (1, errno, "cannot write %s", entfilename);
+ if (p->tag)
+ {
+ if (fprintf (entfile, "T%s\n", p->tag) == EOF)
+ error (1, errno, "cannot write %s", entfilename);
+ }
+ else if (p->date)
+ {
+ if (fprintf (entfile, "D%s\n", p->date) == EOF)
+ error (1, errno, "cannot write %s", entfilename);
+ }
+ else if (fprintf (entfile, "\n") == EOF)
+ 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);
+ 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);
+}
+
+/*
+ * Removes the argument file from the Entries file if necessary.
+ */
+void
+Scratch_Entry (list, fname)
+ List *list;
+ char *fname;
+{
+ Node *node;
+
+ if (trace)
+ (void) fprintf (stderr, "-> Scratch_Entry(%s)\n", fname);
+
+ /* hashlookup to see if it is there */
+ if ((node = findnode (list, fname)) != NULL)
+ {
+ delnode (node); /* delete the node */
+ 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)
+ List *list;
+ char *fname;
+ char *vn;
+ char *ts;
+ char *options;
+ char *tag;
+ char *date;
+{
+ Node *node;
+
+ if (trace)
+ (void) fprintf (stderr, "-> Register(%s, %s, %s, %s, %s %s)\n",
+ fname, vn, ts, options, tag ? tag : "",
+ date ? date : "");
+ /* was it already there? */
+ if ((node = findnode (list, fname)) != NULL)
+ {
+ /* take it out */
+ delnode (node);
+
+ /* add the new one and re-write the file */
+ (void) AddEntryNode (list, fname, vn, ts, options, tag, date);
+ if (!noexec)
+ write_entries (list);
+ }
+ else
+ {
+ /* add the new one */
+ node = AddEntryNode (list, fname, vn, ts, options, tag, date);
+
+ if (!noexec)
+ {
+ /* append it to the end */
+ entfilename = CVSADM_ENT;
+ entfile = open_file (entfilename, "a");
+ (void) write_ent_proc (node);
+ if (fclose (entfile) == EOF)
+ error (1, errno, "error closing %s", entfilename);
+ }
+ }
+}
+
+/*
+ * 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);
+}
+
+/*
+ * Read the entries file into a list, hashing on the file name.
+ */
+List *
+ParseEntries (aflag)
+ int aflag;
+{
+ List *entries;
+ char line[MAXLINELEN];
+ char *cp, *user, *vn, *ts, *options;
+ char *tag_or_date, *tag, *date;
+ char *dirtag, *dirdate;
+ int lineno = 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));
+ bzero ((char *) sdtp, 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;
+ }
+
+ again:
+ fpin = fopen (CVSADM_ENT, "r");
+ if (fpin == NULL)
+ error (0, errno, "cannot open %s for reading", CVSADM_ENT);
+ else
+ {
+ while (fgets (line, sizeof (line), fpin) != NULL)
+ {
+ lineno++;
+ if (line[0] == '/')
+ {
+ user = line + 1;
+ if ((cp = index (user, '/')) == NULL)
+ continue;
+ *cp++ = '\0';
+ vn = cp;
+ if ((cp = index (vn, '/')) == NULL)
+ continue;
+ *cp++ = '\0';
+ ts = cp;
+ if ((cp = index (ts, '/')) == NULL)
+ continue;
+ *cp++ = '\0';
+ options = cp;
+ if ((cp = index (options, '/')) == NULL)
+ continue;
+ *cp++ = '\0';
+ tag_or_date = cp;
+ if ((cp = index (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;
+ (void) AddEntryNode (entries, user, vn, ts, options, tag, date);
+ }
+ else
+ {
+ /* try conversion only on first line */
+ if (lineno == 1)
+ {
+ (void) fclose (fpin);
+ check_entries ((char *) NULL);
+ goto again;
+ }
+ }
+ }
+ }
+
+ /* clean up and return */
+ if (fpin)
+ (void) fclose (fpin);
+ if (dirtag)
+ free (dirtag);
+ if (dirdate)
+ free (dirdate);
+ return (entries);
+}
+
+/*
+ * Look at the entries file to determine if it is in the old entries format.
+ * If so, convert it to the new format.
+ */
+void
+check_entries (dir)
+ char *dir;
+{
+ FILE *fpin, *fpout;
+ char tmp[MAXLINELEN];
+ char line[MAXLINELEN];
+ char entname[MAXLINELEN];
+ char entbak[MAXLINELEN];
+ char *cp, *user, *rev, *ts, *opt;
+
+ if (dir != NULL)
+ {
+ (void) sprintf (entname, "%s/%s", dir, CVSADM_ENT);
+ (void) sprintf (entbak, "%s/%s", dir, CVSADM_ENTBAK);
+ }
+ else
+ {
+ (void) strcpy (entname, CVSADM_ENT);
+ (void) strcpy (entbak, CVSADM_ENTBAK);
+ }
+
+ fpin = open_file (entname, "r");
+ if (fgets (line, sizeof (line), fpin) == NULL)
+ {
+ (void) fclose (fpin);
+ return;
+ }
+ (void) fclose (fpin);
+ if (line[0] != '/')
+ {
+ rename_file (entname, entbak);
+ fpin = open_file (entbak, "r");
+ fpout = open_file (entname, "w+");
+ while (fgets (line, sizeof (line), fpin) != NULL)
+ {
+ if (line[0] == '/')
+ {
+ if (fputs (line, fpout) == EOF)
+ error (1, errno, "cannot write %s", CVSADM_ENT);
+ continue;
+ }
+ rev = line;
+ if ((ts = index (line, '|')) == NULL)
+ continue;
+ *ts++ = '\0';
+ if ((user = rindex (ts, ' ')) == NULL)
+ continue;
+ *user++ = '\0';
+ if ((cp = index (user, '|')) == NULL)
+ continue;
+ *cp = '\0';
+ opt = "";
+#ifdef HAVE_RCS5
+#ifdef HAD_RCS4
+ opt = "-V4";
+#endif
+#endif
+ if (fprintf (fpout, "/%s/%s/%s/%s/\n", user, rev, ts, opt) == EOF)
+ error (1, errno, "cannot write %s", CVSADM_ENT);
+ }
+ (void) fclose (fpin);
+ if (fclose (fpout) == EOF)
+ error (1, errno, "cannot close %s", entname);
+
+ /* clean up any old Files or Mod files */
+ if (dir != NULL)
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM_FILE);
+ else
+ (void) strcpy (tmp, CVSADM_FILE);
+ if (isfile (tmp))
+ (void) unlink (tmp);
+
+ if (dir != NULL)
+ (void) sprintf (tmp, "%s/%s", dir, CVSADM_MOD);
+ else
+ (void) strcpy (tmp, CVSADM_MOD);
+ if (isfile (tmp))
+ (void) unlink (tmp);
+ }
+}
+
+/*
+ * 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;
+ free (p->version);
+ free (p->timestamp);
+ free (p->options);
+ if (p->tag)
+ free (p->tag);
+ if (p->date)
+ free (p->date);
+ free ((char *) p);
+}
+
+/*
+ * Get an Entries file list node, initialize it, and add it to the specified
+ * list
+ */
+static Node *
+AddEntryNode (list, name, version, timestamp, options, tag, date)
+ List *list;
+ char *name;
+ char *version;
+ char *timestamp;
+ char *options;
+ char *tag;
+ char *date;
+{
+ Node *p;
+ Entnode *entdata;
+
+ /* 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 */
+ p->key = xstrdup (name);
+
+ /* malloc the data parts and fill them in */
+ p->data = xmalloc (sizeof (Entnode));
+ entdata = (Entnode *) p->data;
+ entdata->version = xstrdup (version);
+ entdata->timestamp = xstrdup (timestamp);
+ entdata->options = xstrdup (options);
+ if (entdata->options == NULL)
+ entdata->options = xstrdup ("");/* must be non-NULL */
+ entdata->tag = xstrdup (tag);
+ entdata->date = xstrdup (date);
+
+ /* put the node into the list */
+ if (addnode (list, p) != 0)
+ error (0, 0, "Duplicate filename in entries file (%s) -- ignored",
+ name);
+
+ 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) == EOF)
+ error (1, errno, "write to %s failed", tmp);
+ }
+ else
+ {
+ if (fprintf (fout, "D%s\n", date) == EOF)
+ error (1, errno, "write to %s failed", tmp);
+ }
+ if (fclose (fout) == EOF)
+ error (1, errno, "cannot close %s", tmp);
+ }
+ else
+ (void) unlink_file (tmp);
+}
+
+/*
+ * Parse the CVS/Tag file for the current directory.
+ */
+void
+ParseTag (tagp, datep)
+ char **tagp;
+ char **datep;
+{
+ FILE *fp;
+ char line[MAXLINELEN];
+ char *cp;
+
+ if (tagp)
+ *tagp = (char *) NULL;
+ if (datep)
+ *datep = (char *) NULL;
+ fp = fopen (CVSADM_TAG, "r");
+ if (fp)
+ {
+ if (fgets (line, sizeof (line), fp) != NULL)
+ {
+ if ((cp = rindex (line, '\n')) != NULL)
+ *cp = '\0';
+ if (*line == 'T' && tagp)
+ *tagp = xstrdup (line + 1);
+ else if (*line == 'D' && datep)
+ *datep = xstrdup (line + 1);
+ }
+ (void) fclose (fp);
+ }
+}
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..187bd23
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/find_names.c
@@ -0,0 +1,272 @@
+/*
+ * 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.3 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 char rcsid[] = "@(#)find_names.c 1.38 92/04/10";
+#endif
+
+#if __STDC__
+static int find_dirs (char *dir, List * list, int checkadm);
+static int find_rcs (char *dir, List * list);
+#else
+static int find_rcs ();
+static int find_dirs ();
+#endif /* __STDC__ */
+
+static List *filelist;
+
+/*
+ * add the key from entry on entries list to the files list
+ */
+static int
+add_entries_proc (node)
+ Node *node;
+{
+ 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 (p, q)
+ Node *p, *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 = ParseEntries (aflag);
+
+ if (entries != NULL)
+ {
+ /* walk the entries file adding elements to the files list */
+ (void) walklist (entries, add_entries_proc);
+
+ /* if our caller wanted the entries list, return it; else free it */
+ if (optentries != NULL)
+ *optentries = entries;
+ else
+ dellist (&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;
+ CONST char *regex_err;
+ char line[50];
+ struct direct *dp;
+ DIR *dirp;
+
+ /* set up to read the dir */
+ if ((dirp = opendir (dir)) == NULL)
+ return (1);
+
+ /* set up a regular expression to find the ,v files */
+ (void) sprintf (line, ".*%s$", RCSEXT);
+ if ((regex_err = re_comp (line)) != NULL)
+ error (1, 0, "%s", regex_err);
+
+ /* read the dir, grabbing the ,v files */
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ if (re_exec (dp->d_name))
+ {
+ char *comma;
+
+ comma = rindex (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;
+ CONST char *regex_err;
+ char tmp[PATH_MAX];
+ char admdir[PATH_MAX];
+ struct direct *dp;
+ DIR *dirp;
+
+ /* build a regex to blow off ,v files */
+ (void) sprintf (tmp, ".*%s$", RCSEXT);
+ if ((regex_err = re_comp (tmp)) != NULL)
+ error (1, 0, "%s", regex_err);
+
+ /* 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 ||
+ re_exec (dp->d_name)) /* don't bother stating ,v files */
+ continue;
+
+ (void) sprintf (tmp, "%s/%s", dir, dp->d_name);
+ if (isdir (tmp))
+ {
+ /* check for administration directories (if needed) */
+ if (checkadm)
+ {
+ /* blow off symbolic links to dirs in local dir */
+ if (islink (tmp))
+ continue;
+
+ /* check for new style */
+ (void) sprintf (admdir, "%s/%s", tmp, CVSADM);
+ if (!isdir (admdir))
+ {
+ /* and old style */
+ (void) sprintf (admdir, "%s/%s", tmp, OCVSADM);
+ if (!isdir (admdir))
+ 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..9675c4c
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/history.c
@@ -0,0 +1,1373 @@
+/*
+ *
+ * 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 char rcsid[] = "@(#)history.c 1.31 92/04/10";
+#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;
+
+
+#if __STDC__
+static char *fill_hrec (char *line, struct hrec * hr);
+static int accept_hrec (struct hrec * hr, struct hrec * lr);
+static int select_hrec (struct hrec * hr);
+static int sort_order (CONST PTR l, CONST PTR r);
+static int within (char *find, char *string);
+static time_t date_and_time (char *date_str);
+static void expand_modules (void);
+static void read_hrecs (char *fname);
+static void report_hrecs (void);
+static void save_file (char *dir, char *name, char *module);
+static void save_module (char *module);
+static void save_user (char *name);
+#else
+static int sort_order ();
+static time_t date_and_time ();
+static void save_user ();
+static void save_file ();
+static void save_module ();
+static void expand_modules ();
+static char *fill_hrec ();
+static void read_hrecs ();
+static int within ();
+static int select_hrec ();
+static void report_hrecs ();
+static int accept_hrec ();
+#endif /* __STDC__ */
+
+#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;
+
+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 int histsize;
+static char *histdata;
+static char *histfile; /* Ptr to the history file name */
+
+static char *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",
+ 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 = gnu_getopt (argc, argv, "Tacelow?D:b:f:m:n:p:r:t:u:x:X:")) != -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 (!index (ALL_REC_TYPES, *cp))
+ error (1, 0, "%c is not a valid report type", cp);
+ }
+ (void) strcpy (rec_types, optarg);
+ 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\".");
+
+ if (all_users)
+ save_user ("");
+
+ if (mod_list)
+ expand_modules ();
+
+ if (tag_report)
+ {
+ if (!index (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 && !index (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 */
+ FILE *fp;
+ 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 (!(fp = Fopen (fname, "a"))) /* Some directory not there! */
+ return;
+
+ 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:", 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 (fprintf (fp, "%c%08x|%s|%s|%s|%s|%s\n", type, time ((time_t *) NULL),
+ username, workdir, repos, revs ? revs : "", name) == EOF)
+ error (1, errno, "cannot write to history file: %s", fname);
+ (void) fclose (fp);
+}
+
+/*
+ * 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;
+
+ bzero ((char *) hr, sizeof (*hr));
+ while (isspace (*line))
+ line++;
+ if (!(rtn = index (line, '\n')))
+ return ("");
+ *rtn++ = '\0';
+
+ hr->type = line++;
+ (void) sscanf (line, "%x", &hr->date);
+ while (*line && index ("0123456789abcdefABCDEF", *line))
+ line++;
+ if (*line == '\0')
+ return (rtn);
+
+ line++;
+ NEXT_BAR (user);
+ NEXT_BAR (dir);
+ if ((cp = rindex (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 (index ("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");
+ histdata = cp = xmalloc (i + 2);
+ histsize = i;
+
+ 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 = index (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 (!index (rec_types, *(hr->type)))
+ return (0);
+ if (!index ("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 (index (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 = rindex (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);
+ tm = localtime (&(lr->date));
+ (void) printf ("%c %02d/%02d %02d:%02d %-*s", ty, tm->tm_mon + 1,
+ tm->tm_mday, tm->tm_hour, tm->tm_min, user_len, lr->user);
+
+ (void) sprintf (workdir, "%s%s", lr->dir, lr->end);
+ if ((cp = rindex (workdir, '/')) != NULL)
+ {
+ if (lr->mod && !strcmp (++cp, lr->mod))
+ {
+ (void) strcpy (cp, "*");
+ }
+ }
+ (void) strcpy (repos, lr->repos);
+ if ((cp = rindex (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..8236487
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/ignore.c
@@ -0,0 +1,227 @@
+/*
+ * .cvsignore file support contributed by David G. Grubbs <dgg@ksr.com>
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static char rcsid[] = "@(#)ignore.c 1.13 92/04/03";
+#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 */
+
+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 ()
+{
+ extern char *getenv ();
+ 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);
+
+ /* Then add entries found in repository, if it exists */
+ (void) sprintf (file, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_IGNORE);
+ if (isfile (file))
+ 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);
+ if (isfile (file))
+ 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 */
+ if (!(fp = fopen (file, "r")))
+ return;
+ while (fgets (line, sizeof (line), fp))
+ ign_add (line, hold);
+ (void) fclose (fp);
+}
+
+/* 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);
+}
diff --git a/gnu/usr.bin/cvs/cvs/import.c b/gnu/usr.bin/cvs/cvs/import.c
new file mode 100644
index 0000000..288b9b2
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/import.c
@@ -0,0 +1,1011 @@
+/*
+ * 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.3 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"
+
+#ifndef lint
+static char rcsid[] = "@(#)import.c 1.52 92/03/31";
+#endif
+
+#define FILE_HOLDER ".#cvsxxx"
+
+#if __STDC__
+static char *get_comment (char *user);
+static int add_rcs_file (char *message, char *rcs, char *user, char *vtag,
+ int targc, char *targv[]);
+static int expand_at_signs (char *buf, off_t size, FILE *fp);
+static int add_rev (char *message, char *rcs, char *vfile, char *vers);
+static int add_tags (char *rcs, char *vfile, char *vtag, int targc,
+ char *targv[]);
+static int import_descend (char *message, char *vtag, int targc, char *targv[]);
+static int import_descend_dir (char *message, char *dir, char *vtag,
+ int targc, char *targv[]);
+static int process_import_file (char *message, char *vfile, char *vtag,
+ int targc, char *targv[]);
+static int update_rcs_file (char *message, char *vfile, char *vtag, int targc,
+ char *targv[]);
+static void add_log (int ch, char *fname);
+#else
+static int import_descend ();
+static int process_import_file ();
+static int update_rcs_file ();
+static int add_rev ();
+static int add_tags ();
+static char *get_comment ();
+static int add_rcs_file ();
+static int expand_at_signs ();
+static void add_log ();
+static int import_descend_dir ();
+#endif /* __STDC__ */
+
+static int repos_len;
+static char vhead[50];
+static char vbranch[50];
+static FILE *logfp;
+static char repository[PATH_MAX];
+static int conflicts;
+
+static char *import_usage[] =
+{
+ "Usage: %s %s [-Qq] [-I ign] [-m msg] [-b branch]\n",
+ " repository vendor-tag release-tags...\n",
+ "\t-Q\tReally quiet.\n",
+ "\t-q\tSomewhat quiet.\n",
+ "\t-I ign\tMore files to ignore (! to reset).\n",
+ "\t-b bra\tVendor branch id.\n",
+ "\t-m msg\tLog message.\n",
+ NULL
+};
+
+int
+import (argc, argv)
+ int argc;
+ char *argv[];
+{
+ char message[MAXMESGLEN];
+ char tmpfile[L_tmpnam+1];
+ char *cp;
+ int i, c, msglen, err;
+ List *ulist;
+ Node *p;
+
+ if (argc == -1)
+ usage (import_usage);
+
+ ign_setup ();
+
+ (void) strcpy (vbranch, CVSBRANCH);
+ message[0] = '\0';
+ optind = 1;
+ while ((c = gnu_getopt (argc, argv, "Qqb:m:I:")) != -1)
+ {
+ switch (c)
+ {
+ case 'Q':
+ really_quiet = 1;
+ /* FALL THROUGH */
+ case 'q':
+ quiet = 1;
+ break;
+ case 'b':
+ (void) strcpy (vbranch, optarg);
+ break;
+ case 'm':
+#ifdef FORCE_USE_EDITOR
+ use_editor = TRUE;
+#else
+ use_editor = FALSE;
+#endif
+ if (strlen (optarg) >= (sizeof (message) - 1))
+ {
+ error (0, 0, "warning: message too long; truncated!");
+ (void) strncpy (message, optarg, sizeof (message));
+ message[sizeof (message) - 2] = '\0';
+ }
+ else
+ (void) strcpy (message, optarg);
+ break;
+ case 'I':
+ ign_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 (argv[0][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 = rindex (vhead, '.');
+ *cp = '\0';
+ if (use_editor)
+ do_editor ((char *) NULL, message, repository, (List *) NULL);
+ msglen = strlen (message);
+ if (msglen == 0 || message[msglen - 1] != '\n')
+ {
+ message[msglen] = '\n';
+ message[msglen + 1] = '\0';
+ }
+
+ /*
+ * Make all newly created directories writable. Should really use a more
+ * sophisticated security mechanism here.
+ */
+ (void) umask (2);
+ 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);
+ 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 direct *dp;
+ int err = 0;
+ int has_dirs = 0;
+ FILE *links = (FILE *)0;
+
+ /* first, load up any per-directory ignore lists */
+ ign_add_file (CVSDOTIGNORE, 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))
+ {
+ add_log ('I', dp->d_name);
+ continue;
+ }
+ if (isdir (dp->d_name))
+ {
+ has_dirs = 1;
+ }
+ else
+ {
+ if (islink (dp->d_name))
+ {
+#ifdef DO_LINKS
+ char lnbuf[PATH_MAX];
+ int lln;
+
+ add_log ('L', dp->d_name);
+ if ((lln = readlink(dp->d_name, lnbuf, PATH_MAX)) == -1) {
+ error(0, errno, "Can't read contents of symlink %s",
+ dp->d_name);
+ return (1);
+ }
+ else {
+ if (!links) {
+ char lnrep[PATH_MAX];
+
+ sprintf(lnrep, "%s/SymLinks", repository);
+ links = fopen(lnrep, "a+");
+ if (!links) {
+ error (0, errno,
+ "Can't open SymLinks file %s", lnrep);
+ return (1);
+ }
+ }
+ lnbuf[lln] = '\0';
+ fputs(dp->d_name, links);
+ fputc('\n', links);
+ fputs(lnbuf, links);
+ fputc('\n', links);
+ }
+#else
+ add_log ('L', dp->d_name);
+ err++;
+#endif
+ }
+ else
+ {
+ err += process_import_file (message, dp->d_name,
+ vtag, targc, targv);
+ }
+ }
+ }
+ (void) closedir (dirp);
+ }
+ if (has_dirs)
+ {
+ if ((dirp = opendir (".")) == NULL)
+ err++;
+ else
+ {
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ if (!strcmp(".", dp->d_name) || !strcmp("..", dp->d_name))
+ continue;
+ if (!isdir (dp->d_name) || ign_name (dp->d_name))
+ continue;
+ err += import_descend_dir (message, dp->d_name,
+ vtag, targc, targv);
+ /* need to re-load .cvsignore after each dir traversal */
+ ign_add_file (CVSDOTIGNORE, 1);
+ }
+ (void) closedir (dirp);
+ }
+ }
+ if (links)
+ fclose(links);
+ 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];
+
+ (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));
+ }
+ }
+
+ /*
+ * an rcs file exists. have to do things the official, slow, way.
+ */
+ return (update_rcs_file (message, vfile, vtag, targc, targv));
+}
+
+/*
+ * 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)
+ char *message;
+ char *vfile;
+ char *vtag;
+ int targc;
+ char *targv[];
+{
+ Vers_TS *vers;
+ char letter;
+ int ierrno;
+
+ vers = Version_TS (repository, (char *) NULL, vbranch, (char *) NULL, vfile,
+ 1, 0, (List *) NULL, (List *) NULL);
+ if (vers->vn_rcs != NULL)
+ {
+ char xtmpfile[50];
+ int different;
+ int retcode = 0;
+
+ /* XXX - should be more unique */
+ (void) sprintf (xtmpfile, "/tmp/%s", FILE_HOLDER);
+
+ /*
+ * 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);
+ }
+ different = xcmp (xtmpfile, vfile);
+ (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 ||
+ 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;
+ int retcode = 0;
+
+ if (noexec)
+ return (0);
+
+ locked = 0;
+ if (vers != NULL)
+ {
+ run_setup ("%s%s -q -l%s", Rcsbin, RCS, vbranch);
+ run_arg (rcs);
+ if ((retcode = run_exec (RUN_TTY, DEVNULL, DEVNULL, RUN_NORMAL)) == 0)
+ locked = 1;
+ else if (retcode == -1)
+ {
+ error (0, errno, "fork failed");
+ return (1);
+ }
+ }
+ if (link_file (vfile, FILE_HOLDER) < 0)
+ {
+ if (errno == EEXIST)
+ {
+ (void) unlink_file (FILE_HOLDER);
+ (void) link_file (vfile, FILE_HOLDER);
+ }
+ else
+ {
+ ierrno = errno;
+ fperror (logfp, 0, ierrno, "ERROR: cannot create link to %s", vfile);
+ error (0, ierrno, "ERROR: cannot create link to %s", vfile);
+ return (1);
+ }
+ }
+ run_setup ("%s%s -q -f -r%s", Rcsbin, RCS_CI, vbranch);
+ run_args ("-m%s", message);
+ run_arg (rcs);
+ status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ ierrno = errno;
+ rename_file (FILE_HOLDER, vfile);
+ 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)
+ {
+ run_setup ("%s%s -q -u%s", Rcsbin, RCS, vbranch);
+ run_arg (rcs);
+ (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ }
+ 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);
+
+ run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, vtag, vbranch);
+ run_arg (rcs);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 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++)
+ {
+ run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, targv[i], vers->vn_rcs);
+ run_arg (rcs);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 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;
+};
+
+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", "-- ",
+ "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* */
+ "csh", "# ", /* shell */
+ "e", "# ", /* efl */
+ "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 */
+ "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 */
+ "tex", "% ", /* tex */
+ "y", " * ", /* yacc */
+ "ye", " * ", /* yacc-efl */
+ "yr", " * ", /* yacc-ratfor */
+ "", "# ", /* 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 = rindex (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], altdate2[50];
+ char *author, *buf;
+ int i, mode, ierrno, err = 0;
+
+ if (noexec)
+ return (0);
+
+ fprcs = open_file (rcs, "w+");
+ fpuser = open_file (user, "r");
+
+ /*
+ * putadmin()
+ */
+ if (fprintf (fprcs, "head %s;\n", vhead) == EOF ||
+ fprintf (fprcs, "branch %s;\n", vbranch) == EOF ||
+ fprintf (fprcs, "access ;\n") == EOF ||
+ fprintf (fprcs, "symbols ") == EOF)
+ {
+ goto write_error;
+ }
+
+ for (i = targc - 1; i >= 0; i--) /* RCS writes the symbols backwards */
+ if (fprintf (fprcs, "%s:%s.1 ", targv[i], vbranch) == EOF)
+ goto write_error;
+
+ if (fprintf (fprcs, "%s:%s;\n", vtag, vbranch) == EOF ||
+ fprintf (fprcs, "locks ; strict;\n") == EOF ||
+ /* XXX - make sure @@ processing works in the RCS file */
+ fprintf (fprcs, "comment @%s@;\n\n", get_comment (user)) == EOF)
+ {
+ goto write_error;
+ }
+
+ /*
+ * puttree()
+ */
+ (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);
+ now++;
+#ifdef HAVE_RCS5
+ ftm = gmtime (&now);
+#else
+ ftm = localtime (&now);
+#endif
+ (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);
+ author = getcaller ();
+
+ if (fprintf (fprcs, "\n%s\n", vhead) == EOF ||
+ fprintf (fprcs, "date %s; author %s; state Exp;\n",
+ altdate1, author) == EOF ||
+ fprintf (fprcs, "branches %s.1;\n", vbranch) == EOF ||
+ fprintf (fprcs, "next ;\n") == EOF ||
+ fprintf (fprcs, "\n%s.1\n", vbranch) == EOF ||
+ fprintf (fprcs, "date %s; author %s; state Exp;\n",
+ altdate2, author) == EOF ||
+ fprintf (fprcs, "branches ;\n") == EOF ||
+ fprintf (fprcs, "next ;\n\n") == EOF ||
+ /*
+ * putdesc()
+ */
+ fprintf (fprcs, "\ndesc\n") == EOF ||
+ fprintf (fprcs, "@@\n\n\n") == EOF ||
+ /*
+ * putdelta()
+ */
+ fprintf (fprcs, "\n%s\n", vhead) == EOF ||
+ fprintf (fprcs, "log\n") == EOF ||
+ fprintf (fprcs, "@Initial revision\n@\n") == EOF ||
+ fprintf (fprcs, "text\n@") == EOF)
+ {
+ goto write_error;
+ }
+
+ if (fstat (fileno (fpuser), &sb) < 0)
+ error (1, errno, "cannot fstat %s", user);
+ 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) == EOF)
+ goto write_error;
+ free (buf);
+ }
+ if (fprintf (fprcs, "@\n\n") == EOF ||
+ fprintf (fprcs, "\n%s.1\n", vbranch) == EOF ||
+ fprintf (fprcs, "log\n@") == EOF ||
+ expand_at_signs (message, (off_t) strlen (message), fprcs) == EOF ||
+ fprintf (fprcs, "@\ntext\n") == EOF ||
+ fprintf (fprcs, "@@\n") == EOF)
+ {
+ goto write_error;
+ }
+ if (fclose (fprcs) == EOF)
+ {
+ ierrno = errno;
+ goto write_error_noclose;
+ }
+ (void) fclose (fpuser);
+
+ /*
+ * Fix the modes on the RCS files. They must maintain the same modes as
+ * the original user file, except that all write permissions must be
+ * turned off.
+ */
+ mode = sb.st_mode & ~(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++;
+ }
+ 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");
+ }
+ return (err + 1);
+}
+
+/*
+ * Sigh.. need to expand @ signs into double @ signs
+ */
+static int
+expand_at_signs (buf, size, fp)
+ char *buf;
+ off_t size;
+ FILE *fp;
+{
+ char *cp, *end;
+
+ for (cp = buf, end = buf + size; cp < end; cp++)
+ {
+ if (*cp == '@')
+ (void) putc ('@', fp);
+ if (putc (*cp, fp) == EOF)
+ return (EOF);
+ }
+ return (1);
+}
+
+/*
+ * Write an update message to (potentially) the screen and the log file.
+ */
+static void
+add_log (ch, fname)
+ char 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[];
+{
+ char cwd[PATH_MAX];
+ char *cp;
+ int ierrno, err;
+
+ if (islink (dir))
+ return (0);
+ if (getwd (cwd) == NULL)
+ {
+ fperror (logfp, 0, 0, "ERROR: cannot get working directory: %s", cwd);
+ error (0, 0, "ERROR: cannot get working directory: %s", cwd);
+ return (1);
+ }
+ if (repository[0] == '\0')
+ (void) strcpy (repository, dir);
+ else
+ {
+ (void) strcat (repository, "/");
+ (void) strcat (repository, dir);
+ }
+ if (!quiet)
+ error (0, 0, "Importing %s", repository);
+ 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;
+ }
+ if (!isdir (repository))
+ {
+ 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 && 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 = rindex (repository, '/')) != NULL)
+ *cp = '\0';
+ else
+ repository[0] = '\0';
+ if (chdir (cwd) < 0)
+ error (1, errno, "cannot chdir to %s", 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..5da23b3
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/lock.c
@@ -0,0 +1,522 @@
+/*
+ * 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.3 kit.
+ *
+ * Set Lock
+ *
+ * Lock file support for CVS.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static char rcsid[] = "@(#)lock.c 1.42 92/04/10";
+#endif
+
+extern char *ctime ();
+
+#if __STDC__
+static int readers_exist (char *repository);
+static int set_lock (char *lockdir, int will_wait, char *repository);
+static void set_lockers_name (struct stat *statp);
+static int set_writelock_proc (Node * p);
+static int unlock_proc (Node * p);
+static int write_lock (char *repository);
+static void unlock (char *repository);
+static void lock_wait ();
+#else
+static int unlock_proc ();
+static void unlock ();
+static int set_writelock_proc ();
+static int write_lock ();
+static int readers_exist ();
+static int set_lock ();
+static void set_lockers_name ();
+static void lock_wait ();
+#endif /* __STDC__ */
+
+static char lockers_name[20];
+static char *repository;
+static char readlock[PATH_MAX], writelock[PATH_MAX];
+static int cleanup_lckdir;
+static List *locklist;
+
+#define L_OK 0 /* success */
+#define L_ERROR 1 /* error condition */
+#define L_LOCK_OWNED 2 /* lock already owned by us */
+#define L_LOCKED 3 /* 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);
+ locklist = (List *) NULL;
+ }
+}
+
+/*
+ * walklist proc for removing a list of locks
+ */
+static int
+unlock_proc (p)
+ Node *p;
+{
+ 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];
+ struct stat sb;
+
+ if (readlock[0] != '\0')
+ {
+ (void) sprintf (tmp, "%s/%s", repository, readlock);
+ (void) unlink (tmp);
+ }
+
+ if (writelock[0] != '\0')
+ {
+ (void) sprintf (tmp, "%s/%s", repository, writelock);
+ (void) unlink (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.
+ */
+ (void) sprintf (tmp, "%s/%s", repository, CVSLCK);
+ if (stat (tmp, &sb) != -1 && sb.st_uid == geteuid () &&
+ (writelock[0] != '\0' || (readlock[0] != '\0' && cleanup_lckdir)))
+ {
+ (void) rmdir (tmp);
+ }
+ cleanup_lckdir = 0;
+}
+
+/*
+ * 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, "%s.%d", CVSRFL, getpid ());
+
+ /* remember what we're locking (for lock_cleanup) */
+ repository = xrepository;
+
+ /* make sure we clean up on error */
+ (void) SIG_register (SIGHUP, Lock_Cleanup);
+ (void) SIG_register (SIGINT, Lock_Cleanup);
+ (void) SIG_register (SIGQUIT, Lock_Cleanup);
+ (void) SIG_register (SIGPIPE, Lock_Cleanup);
+ (void) SIG_register (SIGTERM, Lock_Cleanup);
+
+ /* make sure we can write the repository */
+ (void) sprintf (tmp, "%s/%s.%d", xrepository, CVSTFL, getpid ());
+ if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF)
+ {
+ error (0, errno, "cannot create read lock in repository `%s'",
+ xrepository);
+ readlock[0] = '\0';
+ (void) unlink (tmp);
+ return (1);
+ }
+ (void) unlink (tmp);
+
+ /* get the lock dir for our own */
+ (void) sprintf (tmp, "%s/%s", xrepository, CVSLCK);
+ if (set_lock (tmp, 1, xrepository) != 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 */
+ (void) sprintf (tmp, "%s/%s", xrepository, CVSLCK);
+ if (rmdir (tmp) < 0)
+ error (0, errno, "failed to remove lock dir `%s'", tmp);
+
+ 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);
+
+ 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)
+ Node *p;
+{
+ /* 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, "%s.%d", CVSWFL, getpid ());
+
+ /* make sure we clean up on error */
+ (void) SIG_register (SIGHUP, Lock_Cleanup);
+ (void) SIG_register (SIGINT, Lock_Cleanup);
+ (void) SIG_register (SIGQUIT, Lock_Cleanup);
+ (void) SIG_register (SIGPIPE, Lock_Cleanup);
+ (void) SIG_register (SIGTERM, Lock_Cleanup);
+
+ /* make sure we can write the repository */
+ (void) sprintf (tmp, "%s/%s.%d", repository, CVSTFL, getpid ());
+ if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF)
+ {
+ error (0, errno, "cannot create write lock in repository `%s'",
+ repository);
+ (void) unlink (tmp);
+ return (L_ERROR);
+ }
+ (void) unlink (tmp);
+
+ /* make sure the lock dir is ours (not necessarily unique to us!) */
+ (void) sprintf (tmp, "%s/%s", repository, CVSLCK);
+ status = set_lock (tmp, 0, repository);
+ if (status == L_OK || status == L_LOCK_OWNED)
+ {
+ /* 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)
+ {
+ if (rmdir (tmp) < 0)
+ error (0, errno, "failed to remove lock dir `%s'", tmp);
+ }
+
+ /* 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;
+
+ (void) unlink (tmp);
+ /* free the lock dir if we created it */
+ if (status == L_OK)
+ {
+ (void) sprintf (tmp, "%s/%s", repository, CVSLCK);
+ if (rmdir (tmp) < 0)
+ error (0, errno, "failed to remove lock dir `%s'", tmp);
+ }
+
+ /* 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 direct *dp;
+ struct stat sb;
+ CONST char *regex_err;
+ int ret = 0;
+
+#ifdef CVS_FUDGELOCKS
+again:
+#endif
+
+ if ((dirp = opendir (repository)) == NULL)
+ error (1, 0, "cannot open directory %s", repository);
+
+ (void) sprintf (line, "^%s.*", CVSRFL);
+ if ((regex_err = re_comp (line)) != NULL)
+ error (1, 0, "%s", regex_err);
+
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ (void) sprintf (line, "%s/%s", repository, dp->d_name);
+ if (re_exec (dp->d_name))
+ {
+#ifdef CVS_FUDGELOCKS
+ time_t now;
+
+ (void) time (&now);
+
+ /*
+ * 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 (stat (line, &sb) != -1)
+ {
+ if (now >= (sb.st_ctime + CVSLCKAGE) && unlink (line) != -1)
+ {
+ (void) closedir (dirp);
+ goto again;
+ }
+ set_lockers_name (&sb);
+ }
+#else
+ if (stat (line, &sb) != -1)
+ set_lockers_name (&sb);
+#endif
+ ret = 1;
+ break;
+ }
+ }
+ (void) 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%d", 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 (lockdir, will_wait, repository)
+ char *lockdir;
+ int will_wait;
+ char *repository;
+{
+ struct stat sb;
+#ifdef CVS_FUDGELOCKS
+ time_t now;
+#endif
+
+ /*
+ * 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 (;;)
+ {
+ SIG_beginCrSect ();
+ if (mkdir (lockdir, 0777) == 0)
+ {
+ cleanup_lckdir = 1;
+ SIG_endCrSect ();
+ return (L_OK);
+ }
+ SIG_endCrSect ();
+
+ 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 (lockdir, &sb) < 0)
+ {
+ if (errno == ENOENT)
+ continue;
+
+ error (0, errno, "couldn't stat lock directory `%s'", lockdir);
+ return (L_ERROR);
+ }
+
+ /*
+ * if we already own the lock, go ahead and return 1 which means it
+ * existed but we owned it
+ */
+ if (sb.st_uid == geteuid () && !will_wait)
+ return (L_LOCK_OWNED);
+
+#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))
+ {
+ if (rmdir (lockdir) >= 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);
+ }
+}
+
+/*
+ * 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..9e7ab8b
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/log.c
@@ -0,0 +1,132 @@
+/*
+ * 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.3 kit.
+ *
+ * Print Log Information
+ *
+ * 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 char rcsid[] = "@(#)log.c 1.39 92/03/31";
+#endif
+
+#if __STDC__
+static Dtype log_dirproc (char *dir, char *repository, char *update_dir);
+static int log_fileproc (char *file, char *update_dir, char *repository,
+ List * entries, List * srcfiles);
+#else
+static int log_fileproc ();
+static Dtype log_dirproc ();
+#endif /* __STDC__ */
+
+static char options[PATH_MAX];
+
+static char *log_usage[] =
+{
+ "Usage: %s %s [-l] [rlog-options] [files...]\n",
+ "\t-l\tLocal directory only, no recursion.\n",
+ NULL
+};
+
+int
+cvslog (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+ int numopt = 1;
+ int err = 0;
+ int local = 0;
+
+ if (argc == -1)
+ usage (log_usage);
+
+ /*
+ * All 'log' command options except -l are passed directly on to 'rlog'
+ */
+ options[0] = '\0'; /* Assume none */
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-' || argv[i][0] == '\0')
+ {
+ numopt++;
+ switch (argv[i][1])
+ {
+ case 'l':
+ local = 1;
+ break;
+ default:
+ (void) strcat (options, " ");
+ (void) strcat (options, argv[i]);
+ break;
+ }
+ }
+ }
+ argc -= numopt;
+ argv += numopt;
+
+ err = start_recursion (log_fileproc, (int (*) ()) NULL, log_dirproc,
+ (int (*) ()) NULL, argc, argv, local,
+ W_LOCAL | W_REPOS | W_ATTIC, 0, 1,
+ (char *) NULL, 1);
+ 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)
+ {
+ if (!really_quiet)
+ error (0, 0, "nothing known about %s", file);
+ return (1);
+ }
+
+ run_setup ("%s%s %s", Rcsbin, RCS_RLOG, options);
+ run_arg (rcsfile->path);
+ 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/logmsg.c b/gnu/usr.bin/cvs/cvs/logmsg.c
new file mode 100644
index 0000000..ce1da92
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/logmsg.c
@@ -0,0 +1,449 @@
+/*
+ * 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.3 kit.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static char rcsid[] = "@(#)logmsg.c 1.40 92/04/10";
+#endif
+
+#if __STDC__
+static int find_type (Node * p);
+static int fmt_proc (Node * p);
+static int logfile_write (char *repository, char *filter, char *title,
+ char *message, char *revision, FILE * logfp,
+ List * changes);
+static int rcsinfo_proc (char *repository, char *template);
+static int title_proc (Node * p);
+static int update_logfile_proc (char *repository, char *filter);
+static void setup_tmpfile (FILE * xfp, char *xprefix, List * changes);
+static int editinfo_proc (char *repository, char *template);
+#else
+static void setup_tmpfile ();
+static int find_type ();
+static int fmt_proc ();
+static int rcsinfo_proc ();
+static int update_logfile_proc ();
+static int title_proc ();
+static int logfile_write ();
+static int editinfo_proc ();
+#endif /* __STDC__ */
+
+static FILE *fp;
+static char *strlist;
+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) != 0)
+ {
+ (void) fprintf (fp, "%sModified Files:\n", prefix);
+ (void) fprintf (fp, "%s\t", prefix);
+ col = 8;
+ (void) walklist (changes, fmt_proc);
+ (void) fprintf (fp, "\n");
+ }
+ type = T_ADDED;
+ if (walklist (changes, find_type) != 0)
+ {
+ (void) fprintf (fp, "%sAdded Files:\n", prefix);
+ (void) fprintf (fp, "%s\t", prefix);
+ col = 8;
+ (void) walklist (changes, fmt_proc);
+ (void) fprintf (fp, "\n");
+ }
+ type = T_REMOVED;
+ if (walklist (changes, find_type) != 0)
+ {
+ (void) fprintf (fp, "%sRemoved Files:\n", prefix);
+ (void) fprintf (fp, "%s\t", prefix);
+ col = 8;
+ (void) walklist (changes, fmt_proc);
+ (void) fprintf (fp, "\n");
+ }
+}
+
+/*
+ * Looks for nodes of a specified type and returns 1 if found
+ */
+static int
+find_type (p)
+ Node *p;
+{
+ 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)
+ Node *p;
+{
+ 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, message, repository, changes)
+ char *dir;
+ char *message;
+ char *repository;
+ List *changes;
+{
+ static int reuse_log_message = 0;
+ char line[MAXLINELEN], fname[L_tmpnam+1];
+ char *orig_message;
+ struct stat pre_stbuf, post_stbuf;
+ int retcode = 0;
+
+ if (noexec || reuse_log_message)
+ return;
+
+ orig_message = xstrdup (message); /* save it for later */
+
+ /* Create a temporary file */
+ (void) tmpnam (fname);
+ again:
+ if ((fp = fopen (fname, "w+")) == NULL)
+ error (1, 0, "cannot create temporary file %s", fname);
+
+ /* set up the file so that the first line is blank if no msg specified */
+ if (*orig_message)
+ {
+ (void) fprintf (fp, "%s", orig_message);
+ if (orig_message[strlen (orig_message) - 1] != '\n')
+ (void) fprintf (fp, "\n");
+ }
+ else
+ (void) fprintf (fp, "\n");
+
+ /* 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)
+ (void) fprintf (fp, "%sCommitting in %s\n%s\n", CVSEDITPREFIX,
+ dir, CVSEDITPREFIX);
+ setup_tmpfile (fp, CVSEDITPREFIX, changes);
+ (void) fprintf (fp,
+ "%s----------------------------------------------------------------------\n",
+ CVSEDITPREFIX);
+
+ /* finish off the temp file */
+ (void) fclose (fp);
+ if (stat (fname, &pre_stbuf) == -1)
+ pre_stbuf.st_mtime = 0;
+
+ if (editinfo_editor)
+ free (editinfo_editor);
+ editinfo_editor = (char *) 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 message variable */
+ fp = open_file (fname, "r");
+ *message = '\0';
+ while (fgets (line, sizeof (line), fp) != NULL)
+ {
+ if (strncmp (line, CVSEDITPREFIX, sizeof (CVSEDITPREFIX) - 1) == 0)
+ continue;
+ if (((int) strlen (message) + (int) strlen (line)) >= MAXMESGLEN)
+ {
+ error (0, 0, "warning: log message truncated!");
+ break;
+ }
+ (void) strcat (message, line);
+ }
+ (void) fclose (fp);
+ if ((stat (fname, &post_stbuf) == 0 &&
+ pre_stbuf.st_mtime == post_stbuf.st_mtime) ||
+ (*message == '\0' || strcmp (message, "\n") == 0))
+ {
+ for (;;)
+ {
+ (void) printf ("\nLog message unchanged or not specified\n");
+ (void) printf ("a)bort, c)continue, e)dit, !)reuse this message unchanged for remaining dirs\n");
+ (void) printf ("Action: (continue) ");
+ (void) fflush (stdout);
+ *line = '\0';
+ (void) fgets (line, sizeof (line), stdin);
+ if (*line == '\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");
+ }
+ }
+ free (orig_message);
+ (void) unlink_file (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;
+ char line[MAXLINELEN];
+
+ /* 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)
+ {
+ while (fgets (line, sizeof (line), tfp) != NULL)
+ (void) fputs (line, fp);
+ (void) fclose (tfp);
+ return (0);
+ }
+ else
+ {
+ error (0, 0, "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;
+
+ /* 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 (!strlist)
+ strlist = xmalloc (MAXLISTLEN);
+ strlist[0] = '\0';
+
+ type = T_TITLE;
+ (void) walklist (changes, title_proc);
+ type = T_ADDED;
+ (void) walklist (changes, title_proc);
+ type = T_MODIFIED;
+ (void) walklist (changes, title_proc);
+ type = T_REMOVED;
+ (void) walklist (changes, title_proc);
+ title = xmalloc (strlen (srepos) + strlen (strlist) + 1 + 2); /* for 's */
+ (void) sprintf (title, "'%s%s'", srepos, strlist);
+
+ /* to be nice, free up this chunk of memory */
+ free (strlist);
+ strlist = (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 strlist
+ */
+static int
+title_proc (p)
+ Node *p;
+{
+ if (p->data == (char *) type)
+ {
+ (void) strcat (strlist, " ");
+ (void) strcat (strlist, 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], host[MAXHOSTNAMELEN];
+ FILE *pipefp, *Popen ();
+ char *prog = xmalloc (MAXPROGLEN);
+ char *cp;
+ int c;
+
+ /*
+ * 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);
+ }
+ if (gethostname (host, sizeof (host)) < 0)
+ (void) strcpy (host, "(unknown)");
+ (void) fprintf (pipefp, "Update of %s\n", repository);
+ (void) fprintf (pipefp, "In directory %s:%s\n\n", host,
+ ((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");
+ (void) 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..d6ad258
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/main.c
@@ -0,0 +1,460 @@
+/*
+ * 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.3 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
+ * 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"
+
+char rcsid[] = "@(#)main.c 1.64 92/03/31\n";
+
+extern char *getenv ();
+
+char *program_name;
+char *command_name = "";
+
+int use_editor = TRUE;
+int cvswrite = !CVSREAD_DFLT;
+int really_quiet = FALSE;
+int quiet = FALSE;
+int trace = FALSE;
+int noexec = FALSE;
+int logoff = FALSE;
+
+char *CurDir;
+
+/*
+ * Defaults, for the environment variables that are not set
+ */
+char *Rcsbin = RCSBIN_DFLT;
+char *Editor = EDITOR_DFLT;
+char *CVSroot = CVSROOT_DFLT;
+
+#if __STDC__
+int add (int argc, char **argv);
+int admin (int argc, char **argv);
+int checkout (int argc, char **argv);
+int commit (int argc, char **argv);
+int diff (int argc, char **argv);
+int history (int argc, char **argv);
+int import (int argc, char **argv);
+int cvslog (int argc, char **argv);
+int patch (int argc, char **argv);
+int release (int argc, char **argv);
+int cvsremove (int argc, char **argv);
+int rtag (int argc, char **argv);
+int status (int argc, char **argv);
+int tag (int argc, char **argv);
+int update (int argc, char **argv);
+#else
+int add ();
+int admin ();
+int checkout ();
+int commit ();
+int diff ();
+int history ();
+int import ();
+int cvslog ();
+int patch ();
+int release ();
+int cvsremove ();
+int rtag ();
+int status ();
+int tag ();
+int update ();
+#endif /* __STDC__ */
+
+#ifdef FREEBSD_DEVELOPER
+int freebsd = TRUE; /* Use the FreeBSD -K flags!! */
+#endif
+
+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. */
+} cmds[] =
+
+{
+ { "add", "ad", "new", add },
+ { "admin", "adm", "rcs", admin },
+ { "checkout", "co", "get", checkout },
+ { "commit", "ci", "com", commit },
+ { "diff", "di", "dif", diff },
+ { "export", "exp", "ex", checkout },
+ { "history", "hi", "his", history },
+ { "import", "im", "imp", import },
+ { "log", "lo", "rlog", cvslog },
+ { "rdiff", "patch", "pa", patch },
+ { "release", "re", "rel", release },
+ { "remove", "rm", "delete", cvsremove },
+ { "status", "st", "stat", status },
+ { "rtag", "rt", "rfreeze", rtag },
+ { "tag", "ta", "freeze", tag },
+ { "update", "up", "upd", update },
+ { NULL, NULL, NULL, NULL },
+};
+
+static char *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",
+ " -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",
+#ifdef FREEBSD_DEVELOPER
+ " -x Do NOT use the FreeBSD -K default flags\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",
+ " 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 SIGTYPE
+main_cleanup ()
+{
+ exit (1);
+}
+
+int
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *version_string;
+ char *cp;
+ struct cmd *cm;
+ int c, help = FALSE, err = 0;
+ int rcsbin_update_env, cvs_update_env;
+ char tmp[PATH_MAX];
+
+ /*
+ * Just save the last component of the path for error messages
+ */
+ if ((program_name = rindex (argv[0], '/')) == NULL)
+ program_name = argv[0];
+ else
+ program_name++;
+
+ CurDir = xmalloc (PATH_MAX);
+ if (!getwd (CurDir))
+ error (1, 0, "cannot get working directory: %s", CurDir);
+
+ /*
+ * 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 */
+ if ((cp = getenv (RCSBIN_ENV)) != NULL)
+ {
+ Rcsbin = cp;
+ rcsbin_update_env = 0; /* it's already there */
+ }
+ if ((cp = getenv (EDITOR_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;
+
+ optind = 1;
+#ifdef FREEBSD_DEVELOPER
+ while ((c = gnu_getopt (argc, argv, "Qqrwtnlvb:e:d:Hx")) != -1)
+#else
+ while ((c = gnu_getopt (argc, argv, "Qqrwtnlvb:e:d:H")) != -1)
+#endif /* FREEBSD_DEVELOPER */
+ {
+ switch (c)
+ {
+ case 'Q':
+ really_quiet = TRUE;
+ /* FALL THROUGH */
+ case 'q':
+ quiet = TRUE;
+ break;
+ case 'r':
+ cvswrite = FALSE;
+ break;
+ case 'w':
+ cvswrite = TRUE;
+ break;
+ case 't':
+ trace = TRUE;
+ break;
+ case 'n':
+ noexec = TRUE;
+ case 'l': /* Fall through */
+ logoff = TRUE;
+ break;
+ case 'v':
+ (void) fputs (rcsid, stdout);
+ (void) fputs (version_string, stdout);
+ (void) sprintf (tmp, "Patch Level: %d\n", PATCHLEVEL);
+ (void) fputs (tmp, stdout);
+ (void) fputs ("\nCopyright (c) 1992, Brian Berliner and Jeff Polk\nCopyright (c) 1989-1992, Brian Berliner\n\nCVS may be copied only under the terms of the GNU General Public License,\na copy of which can be found with the CVS 1.3 distribution kit.\n", stdout);
+ exit (0);
+ 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':
+ help = TRUE;
+ break;
+#ifdef FREEBSD_DEVELOPER
+ case 'x':
+ freebsd = FALSE;
+ break;
+#endif /* FREEBSD_DEVELOPER */
+ case '?':
+ default:
+ usage (usg);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc < 1)
+ usage (usg);
+
+ /*
+ * XXX - Compatibility. This can be removed in the release after CVS 1.3.
+ * Try to rename the CVSROOT.adm file to CVSROOT, unless there already is
+ * a CVSROOT directory.
+ */
+ if (CVSroot != NULL)
+ {
+ char rootadm[PATH_MAX];
+ char orootadm[PATH_MAX];
+
+ (void) sprintf (rootadm, "%s/%s", CVSroot, CVSROOTADM);
+ if (!isdir (rootadm))
+ {
+ (void) sprintf (orootadm, "%s/%s", CVSroot, OCVSROOTADM);
+ if (isdir (orootadm))
+ (void) rename (orootadm, rootadm);
+ }
+ strip_path (CVSroot);
+ }
+
+ /*
+ * 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.
+ */
+ {
+ 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 (access (path, R_OK | X_OK))
+ {
+ save_errno = errno;
+ error (0, 0,
+ "Sorry, you don't have sufficient access to %s", CVSroot);
+ error (1, save_errno, "%s", path);
+ }
+ (void) strcat (path, "/");
+ (void) strcat (path, CVSROOTADM_HISTORY);
+ if (isfile (path) && access (path, R_OK | (logoff ? 0 : 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);
+ }
+ }
+ }
+
+#ifndef PUTENV_MISSING
+ /* 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 */
+ (void) SIG_register (SIGHUP, main_cleanup);
+ (void) SIG_register (SIGINT, main_cleanup);
+ (void) SIG_register (SIGQUIT, main_cleanup);
+ (void) SIG_register (SIGPIPE, main_cleanup);
+ (void) SIG_register (SIGTERM, main_cleanup);
+
+#ifndef SETVBUF_MISSING
+ /*
+ * 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
+
+ err = (*(cm->func)) (argc, argv);
+ }
+ /*
+ * 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 char **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..b0658d7
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/modules.c
@@ -0,0 +1,810 @@
+/*
+ * 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.3 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"
+
+#ifndef lint
+static char rcsid[] = "@(#)modules.c 1.57 92/04/10";
+#endif
+
+struct sortrec
+{
+ char *modname;
+ char *status;
+ char *rest;
+ char *comment;
+};
+
+#if __STDC__
+static int sort_order (CONST PTR l, CONST PTR r);
+static void save_d (char *k, int ks, char *d, int ds);
+#else
+static int sort_order ();
+static void save_d ();
+#endif /* __STDC__ */
+
+
+/*
+ * 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;
+ int (*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 *tag_prog = NULL;
+ char *update_prog = NULL;
+ char cwd[PATH_MAX];
+ char line[MAXLINELEN];
+ char *xmodargv[MAXFILEPERDIR];
+ char **modargv;
+ char *value;
+ char *zvalue;
+ char *mwhere = NULL;
+ char *mfile = NULL;
+ char *spec_opt = NULL;
+ char xvalue[PATH_MAX];
+ int modargc, alias = 0;
+ datum key, val;
+ char *cp;
+ int c, err = 0;
+
+ /* remember where we start */
+ if (getwd (cwd) == NULL)
+ error (1, 0, "cannot get current working directory: %s", cwd);
+
+ /* 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 = index (val.dptr, '#')) != NULL)
+ {
+ do
+ *cp-- = '\0';
+ while (isspace (*cp));
+ }
+ 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 = rindex (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 = rindex (mname, '/')) != NULL && cp != mname)
+ {
+ char *slashp;
+
+ /* put the ' ' in a copy so we don't mess up the original */
+ value = strcpy (xvalue, mname);
+ slashp = rindex (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 = index (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 = index (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 = index (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) && !isfile (OCVSADM))
+ {
+ char nullrepos[PATH_MAX];
+
+ (void) sprintf (nullrepos, "%s/%s/%s", CVSroot,
+ CVSROOTADM, CVSNULLREPOS);
+ if (!isfile (nullrepos))
+ (void) mkdir (nullrepos, 0777);
+ Create_Admin (".", 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);
+ }
+ }
+ 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 (&modargc, xmodargv, line);
+ modargv = xmodargv;
+
+ /* parse the args */
+ optind = 1;
+ while ((c = gnu_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 '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++)
+ 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);
+
+ /* clean up */
+ free_names (&modargc, modargv);
+
+ /* 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 = index (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 */
+ 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 (chdir (cwd) < 0)
+ error (1, errno, "failed chdir to %s!", 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))
+ {
+ /*
+ * If a relative pathname is specified as the checkout or
+ * tag 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 : checkout_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;
+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 = index (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 = index (cp, '#')) != NULL)
+ {
+ if (*--cp2 == ' ')
+ *cp2 = '\0';
+ if (*++cp == ' ')
+ cp++;
+ s_rec->comment = cp;
+ }
+ else
+ s_rec->comment = "";
+
+ s_count++;
+}
+
+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 = 1;
+ wid = 0;
+ while ((c = gnu_getopt (argc, argv, CVSMODULE_OPTS)) != -1)
+ {
+ if (!status)
+ {
+ if (c == 'a')
+ {
+ (void) printf (" -a");
+ 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);
+ }
+ }
+}
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..4057c88
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/no_diff.c
@@ -0,0 +1,85 @@
+/*
+ * 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.3 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 char rcsid[] = "@(#)no_diff.c 1.35 92/03/31";
+#endif
+
+int
+No_Difference (file, vers, entries)
+ char *file;
+ Vers_TS *vers;
+ List *entries;
+{
+ Node *p;
+ char tmp[L_tmpnam+1];
+ int ret;
+ char *ts, *options;
+ int retcode = 0;
+
+ 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 (!iswritable (file)) /* fix the modes as a side effect */
+ xchmod (file, 1);
+
+ /* do the byte by byte compare */
+ if (xcmp (file, tmp) == 0)
+ {
+ if (cvswrite == FALSE) /* fix the modes as a side effect */
+ xchmod (file, 0);
+
+ /* 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);
+ 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 */
+ }
+ else
+ {
+ error (0, retcode == -1 ? errno : 0,
+ "could not check out revision %s of %s", vers->vn_user, file);
+ ret = -1; /* different since we couldn't tell */
+ }
+
+ if (trace)
+ (void) fprintf (stderr, "-> unlink(%s)\n", tmp);
+ (void) unlink (tmp);
+ free (options);
+ return (ret);
+}
diff --git a/gnu/usr.bin/cvs/cvs/parseinfo.c b/gnu/usr.bin/cvs/cvs/parseinfo.c
new file mode 100644
index 0000000..65343f5
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/parseinfo.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.3 kit.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static char rcsid[] = "@(#)parseinfo.c 1.16 92/04/10";
+#endif
+
+/*
+ * Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for
+ * each line in the file that matches the REPOSITORY.
+ * 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;
+ int (*callproc) ();
+ int all;
+{
+ int err = 0;
+ FILE *fp_info;
+ char infopath[PATH_MAX];
+ char line[MAXLINELEN];
+ char *default_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);
+
+ /* 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 = rindex (value, '\n')) != NULL)
+ *cp = '\0';
+
+ /*
+ * 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 (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, value);
+ else
+ error(0, 0, "Keyword `ALL' is ignored at line %d in %s file",
+ line_number, infofile);
+ 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, 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);
+
+ 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..abc02fd
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/patch.c
@@ -0,0 +1,541 @@
+/*
+ * 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.3 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"
+
+#ifndef lint
+static char rcsid[] = "@(#)patch.c 1.50 92/04/10";
+
+#endif
+
+#if __STDC__
+static SIGTYPE patch_cleanup (void);
+static Dtype patch_dirproc (char *dir, char *repos, char *update_dir);
+static int patch_fileproc (char *file, char *update_dir, char *repository,
+ List * entries, List * srcfiles);
+static int patch_proc (int *pargc, char *argv[], char *xwhere,
+ char *mwhere, char *mfile, int shorten,
+ int local_specified, char *mname, char *msg);
+#else
+static int patch_proc ();
+static int patch_fileproc ();
+static Dtype patch_dirproc ();
+static SIGTYPE patch_cleanup ();
+#endif /* __STDC__ */
+
+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 *K_flag1 = NULL;
+static char *K_flag2 = NULL;
+static char tmpfile1[L_tmpnam+1], tmpfile2[L_tmpnam+1], tmpfile3[L_tmpnam+1];
+static int unidiff = 0;
+
+static char *patch_usage[] =
+{
+ "Usage: %s %s [-Qflq] [-c|-u] [-s|-t] [-V %%d]\n",
+ " -r rev|-D date [-r rev2 | -D date2] modules...\n",
+ "\t-Q\tReally quiet.\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",
+ "\t-K key\tUse RCS key -K option on checkout.\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 = gnu_getopt (argc, argv, "V:k:cuftsQqlRD:r:K:")) != -1)
+ {
+ switch (c)
+ {
+ case 'Q':
+ really_quiet = 1;
+ /* FALL THROUGH */
+ case 'q':
+ quiet = 1;
+ 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 'K':
+ if (K_flag2 != NULL)
+ error (1, 0, "no more than two -K flags can be specified");
+ if (K_flag1 != NULL)
+ K_flag2 = optarg;
+ else
+ K_flag1 = optarg;
+ break;
+ case '?':
+ default:
+ usage (patch_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Sanity checks */
+ /* Check for dummy -K flags */
+ if (K_flag1 && K_flag1[0] != 'e' && K_flag1[0] != 'i')
+ error (1, 0, "-K flag does not start e or i");
+ if (K_flag2 && K_flag2[0] != 'e' && K_flag2[0] != 'i')
+ error (1, 0, "-K flag does not start e or i");
+ 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 ("");
+
+ /* clean up if we get a signal */
+ (void) SIG_register (SIGHUP, patch_cleanup);
+ (void) SIG_register (SIGINT, patch_cleanup);
+ (void) SIG_register (SIGQUIT, patch_cleanup);
+ (void) SIG_register (SIGPIPE, patch_cleanup);
+ (void) SIG_register (SIGTERM, patch_cleanup);
+
+ 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 = rindex (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, (int (*) ()) NULL, patch_dirproc,
+ (int (*) ()) NULL, *pargc - 1, argv + 1, local,
+ which, 0, 1, where, 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;
+{
+ 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[MAXLINELEN], line2[MAXLINELEN];
+ 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);
+
+ 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);
+
+ 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)
+ (void) printf ("%s is removed; not included in release %s\n",
+ rcs, rev2 ? rev2 : date2);
+ 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 %s%s", Rcsbin, RCS_CO, options,
+ vers_tag, K_flag1 ? "-K" : "", K_flag1 ? K_flag1 : "");
+ 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;
+ }
+ }
+ else if (toptwo_diffs)
+ {
+ ret = 1;
+ goto out;
+ }
+ if (vers_head != NULL)
+ {
+ run_setup ("%s%s %s -p -q -r%s %s%s", Rcsbin, RCS_CO, options,
+ vers_head, K_flag2 ? "-K" : "", K_flag2 ? K_flag2 : "");
+ 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;
+ }
+ }
+ run_setup ("%s -%c", DIFF, unidiff ? 'u' : 'c');
+ run_arg (tmpfile1);
+ run_arg (tmpfile2);
+ 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.
+ */
+ fp = open_file (tmpfile3, "r");
+ if (fgets (line1, sizeof (line1), fp) == NULL ||
+ fgets (line2, sizeof (line2), fp) == NULL)
+ {
+ 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 = index (line1, '\t')) == NULL ||
+ (cp2 = index (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 = index (line1, '\t')) == NULL ||
+ (cp2 = index (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 = rindex (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);
+ while (fgets (line1, sizeof (line1), fp) != NULL)
+ (void) printf ("%s", line1);
+ (void) fclose (fp);
+ break;
+ default:
+ error (0, 0, "diff failed for %s", rcs);
+ }
+ out:
+ (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 SIGTYPE
+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..dc2214d
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/patchlevel.h
@@ -0,0 +1 @@
+#define PATCHLEVEL 0
diff --git a/gnu/usr.bin/cvs/cvs/rcs.c b/gnu/usr.bin/cvs/cvs/rcs.c
new file mode 100644
index 0000000..e882b8c
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/rcs.c
@@ -0,0 +1,1449 @@
+/*
+ * 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.3 kit.
+ *
+ * The routines contained in this file do all the rcs file parsing and
+ * manipulation
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static char rcsid[] = "@(#)rcs.c 1.28 92/03/31";
+#endif
+
+#if __STDC__
+static char *RCS_getbranch (RCSNode * rcs, char *tag, int force_tag_match);
+static char *RCS_getdatebranch (RCSNode * rcs, char *date, char *branch);
+static int getrcskey (FILE * fp, char **keyp, char **valp);
+static int parse_rcs_proc (Node * file);
+static int checkmagic_proc (Node *p);
+static void do_branches (List * list, char *val);
+static void do_symbols (List * list, char *val);
+static void null_delproc (Node * p);
+static void rcsnode_delproc (Node * p);
+static void rcsvers_delproc (Node * p);
+#else
+static int parse_rcs_proc ();
+static int checkmagic_proc ();
+static void rcsnode_delproc ();
+static void rcsvers_delproc ();
+static void null_delproc ();
+static int getrcskey ();
+static void do_symbols ();
+static void do_branches ();
+static char *RCS_getbranch ();
+static char *RCS_getdatebranch ();
+#endif /* __STDC__ */
+
+static List *rcslist;
+static char *repository;
+
+/*
+ * 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) != 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)
+ Node *file;
+{
+ Node *p;
+ 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)
+ {
+ p = getnode ();
+ p->key = xstrdup (file->key);
+ p->delproc = rcsnode_delproc;
+ p->type = RCSNODE;
+ p->data = (char *) rdata;
+ (void) addnode (rcslist, p);
+ }
+ return (0);
+}
+
+/*
+ * Parse an rcsfile given a user file name and a repository
+ */
+RCSNode *
+RCS_parse (file, repos)
+ char *file;
+ char *repos;
+{
+ RCSNode *rcs;
+ char rcsfile[PATH_MAX];
+
+ (void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT);
+ if (!isreadable (rcsfile))
+ {
+ (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC,
+ file, RCSEXT);
+ if (!isreadable (rcsfile))
+ return (NULL);
+ rcs = RCS_parsercsfile (rcsfile);
+ if (rcs != NULL)
+ {
+ rcs->flags |= INATTIC;
+ rcs->flags |= VALID;
+ }
+ return (rcs);
+ }
+ rcs = RCS_parsercsfile (rcsfile);
+ if (rcs != NULL)
+ rcs->flags |= VALID;
+ return (rcs);
+}
+
+/*
+ * Do the real work of parsing an RCS file
+ */
+RCSNode *
+RCS_parsercsfile (rcsfile)
+ char *rcsfile;
+{
+ Node *q, *r;
+ RCSNode *rdata;
+ RCSVers *vnode;
+ int n;
+ char *cp;
+ char *key, *value;
+ FILE *fp;
+
+ /* open the rcsfile */
+ if ((fp = fopen (rcsfile, "r")) == NULL)
+ {
+ error (0, errno, "Couldn't open rcs file `%s'", rcsfile);
+ return (NULL);
+ }
+
+ /* make a node */
+ rdata = (RCSNode *) xmalloc (sizeof (RCSNode));
+ bzero ((char *) rdata, sizeof (RCSNode));
+ rdata->refcount = 1;
+ rdata->path = xstrdup (rcsfile);
+ 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 */
+ if (getrcskey (fp, &key, &value) == -1 || key == NULL)
+ {
+ if (!really_quiet)
+ error (0, 0, "`%s' does not appear to be a valid rcs file",
+ rcsfile);
+ freercsnode (&rdata);
+ (void) fclose (fp);
+ return (NULL);
+ }
+
+ /* process it */
+ if (strcmp (RCSHEAD, key) == 0 && value != NULL)
+ {
+ rdata->head = xstrdup (value);
+ continue;
+ }
+ if (strcmp (RCSBRANCH, key) == 0 && value != NULL)
+ {
+ rdata->branch = xstrdup (value);
+ if ((numdots (rdata->branch) & 1) != 0)
+ {
+ /* turn it into a branch if it's a revision */
+ cp = rindex (rdata->branch, '.');
+ *cp = '\0';
+ }
+ continue;
+ }
+ if (strcmp (RCSSYMBOLS, key) == 0)
+ {
+ if (value != NULL)
+ {
+ /* if there are tags, set up the tag list */
+ rdata->symbols = getlist ();
+ do_symbols (rdata->symbols, 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 (isspace (*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));
+ bzero (q->data, 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);
+
+ /* 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)
+ {
+ /* 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;
+ }
+
+ (void) fclose (fp);
+ return (rdata);
+}
+
+/*
+ * 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)->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 int keysize = 0;
+static char *value = NULL;
+static int valsize = 0;
+
+#define ALLOCINCR 1024
+
+static int
+getrcskey (fp, keyp, valp)
+ FILE *fp;
+ char **keyp;
+ char **valp;
+{
+ char *cur, *max;
+ int c;
+ int funky = 0;
+ int white = 1;
+
+ /* skip leading whitespace */
+ while (1)
+ {
+ c = getc (fp);
+ if (c == EOF)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+ if (!isspace (c))
+ break;
+ }
+
+ /* fill in key */
+ cur = key;
+ max = key + keysize;
+ while (!isspace (c) && c != ';')
+ {
+ if (cur < max)
+ *cur++ = c;
+ else
+ {
+ 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);
+ }
+ }
+ *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);
+ }
+
+ /* 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 */
+ (void) ungetc (c, fp);
+ cur = value;
+ max = value + valsize;
+
+ /* process the value */
+ for (;;)
+ {
+ /* get a character */
+ c = getc (fp);
+ if (c == EOF)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+
+ /* if we are in funky mode, do the rest of this string */
+ if (funky)
+ {
+
+ /*
+ * funky mode processing does the following: o @@ means one @ o
+ * all other characters are literal up to a single @ (including
+ * ';')
+ */
+ for (;;)
+ {
+ if (c == '@')
+ {
+ c = getc (fp);
+ if (c == EOF)
+ {
+ *keyp = (char *) NULL;
+ *valp = (char *) NULL;
+ return (-1);
+ }
+ if (c != '@')
+ {
+ /* @ followed by non @ turns off funky mode */
+ funky = 0;
+ break;
+ }
+ /* otherwise, we already ate one @ so copy the other one */
+ }
+
+ /* put the character on the value (maybe allocating space) */
+ 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);
+ }
+ }
+ }
+
+ /* if we got the semi-colon we are done with the entire value */
+ if (c == ';')
+ break;
+
+ /* process the character we got */
+ if (white && c == '@')
+ {
+
+ /*
+ * if we are starting a word with an '@', enable funky processing
+ */
+ white = 0; /* you can't be funky and white :-) */
+ funky = 1;
+ }
+ else
+ {
+
+ /*
+ * we put the character on the list, compressing all whitespace
+ * to a single space
+ */
+
+ /* whitespace with white set means compress it out */
+ if (white && isspace (c))
+ continue;
+
+ if (isspace (c))
+ {
+ /* make c a space and set white */
+ white = 1;
+ c = ' ';
+ }
+ else
+ white = 0;
+
+ /* put the char on the end of value (maybe allocating space) */
+ if (cur >= max)
+ {
+ value = xrealloc (value, valsize + ALLOCINCR);
+ cur = value + valsize;
+ valsize += ALLOCINCR;
+ max = value + valsize;
+ }
+ *cur++ = c;
+ }
+ }
+
+ /* if the last char was white space, take it off */
+ if (white && cur != value)
+ cur--;
+
+ /* terminate the string */
+ if (cur)
+ *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 (isspace (*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 = index (cp, ':');
+ *cp++ = '\0';
+ rev = cp;
+ while (!isspace (*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 (isspace (*cp))
+ cp++;
+
+ /* if we got to the end, we are done */
+ if (*cp == '\0')
+ break;
+
+ /* find the end of this branch */
+ branch = cp;
+ while (!isspace (*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)
+ RCSNode *rcs;
+ char *tag;
+ char *date;
+ int force_tag_match;
+{
+ /* make sure we have something to look at... */
+ if (rcs == NULL)
+ return ((char *) 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);
+ if (tagrev == NULL)
+ return ((char *) NULL);
+
+ if ((cp = rindex (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));
+ 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, tag, force_tag_match)
+ RCSNode *rcs;
+ char *tag;
+ int force_tag_match;
+{
+ Node *p;
+
+ /* make sure we have something to look at... */
+ if (rcs == NULL)
+ return ((char *) NULL);
+
+ /* If tag is "HEAD", special case to get head RCS revision */
+ if (tag && (strcmp (tag, TAG_HEAD) == 0 || *tag == '\0'))
+ if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC))
+ return ((char *) NULL); /* head request for removed file */
+ else
+ 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, 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 = rindex (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)
+ 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, checkmagic_proc) != 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)
+ Node *p;
+{
+ if (strcmp (check_rev, p->data) == 0)
+ return (1);
+ else
+ return (0);
+}
+
+/*
+ * 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_isbranch (file, rev, srcfiles)
+ char *file;
+ char *rev;
+ List *srcfiles;
+{
+ int dots;
+ 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;
+ p = findnode (rcs->symbols, 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 = rindex (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, 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 = rindex (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
+ */
+static 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... */
+ if (rcs == NULL)
+ return ((char *) NULL);
+
+ /* find out if the tag contains a dot, or is on the trunk */
+ cp = rindex (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... */
+ if (rcs == NULL)
+ return ((char *) NULL);
+
+ if (rcs->branch)
+ return (RCS_getbranch (rcs, rcs->branch, 1));
+
+ /*
+ * NOTE: we call getbranch with force_tag_match set to avoid any
+ * possibility of recursion
+ */
+ 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... */
+ if (rcs == NULL)
+ return ((char *) NULL);
+
+ /* 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 = rindex (xrev, '.');
+ if (cp == NULL)
+ {
+ free (xrev);
+ return (NULL);
+ }
+ *cp = '\0'; /* turn it into a revision */
+ 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... */
+ if (rcs == NULL)
+ return (revdate);
+
+ /* 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);
+}
+
+/*
+ * 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)
+ char *arg;
+{
+ static char *kflags[] =
+ {"kv", "kvl", "k", "v", "o", (char *) NULL};
+ char karg[10];
+ char **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)
+ {
+ (void) fprintf (stderr, "%s %s: invalid -k option\n",
+ program_name, command_name);
+ (void) fprintf (stderr, "\tvalid options are:\n");
+ for (cpp = kflags; *cpp != NULL; cpp++)
+ (void) fprintf (stderr, "\t\t-k%s\n", *cpp);
+ error (1, 0, "Please retry with a valid -k option");
+ }
+
+ (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)
+ char *tag;
+{
+ char *invalid = "$,.:;@"; /* invalid RCS tag characters */
+ 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 (index (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);
+}
diff --git a/gnu/usr.bin/cvs/cvs/rcs.h b/gnu/usr.bin/cvs/cvs/rcs.h
new file mode 100644
index 0000000..ba5bdae
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/rcs.h
@@ -0,0 +1,102 @@
+/* @(#)rcs.h 1.14 92/03/31 */
+
+/*
+ * 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.3 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 RCSHEAD "head"
+#define RCSBRANCH "branch"
+#define RCSSYMBOLS "symbols"
+#define RCSDATE "date"
+#define RCSDESC "desc"
+#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 */
+struct rcsnode
+{
+ int refcount;
+ int flags;
+ char *path;
+ char *head;
+ char *branch;
+ List *symbols;
+ List *versions;
+ List *dates;
+};
+typedef struct rcsnode RCSNode;
+
+struct rcsversnode
+{
+ char *version;
+ char *date;
+ char *next;
+ 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
+ */
+#if __STDC__
+List *RCS_parsefiles (List * files, char *xrepos);
+RCSNode *RCS_parse (char *file, char *repos);
+RCSNode *RCS_parsercsfile (char *rcsfile);
+char *RCS_check_kflag (char *arg);
+char *RCS_getdate (RCSNode * rcs, char *date, int force_tag_match);
+char *RCS_gettag (RCSNode * rcs, char *tag, int force_tag_match);
+char *RCS_getversion (RCSNode * rcs, char *tag, char *date,
+ int force_tag_match);
+char *RCS_magicrev (RCSNode *rcs, char *rev);
+int RCS_isbranch (char *file, char *rev, List *srcfiles);
+char *RCS_whatbranch (char *file, char *tag, List *srcfiles);
+char *RCS_head (RCSNode * rcs);
+int RCS_datecmp (char *date1, char *date2);
+time_t RCS_getrevtime (RCSNode * rcs, char *rev, char *date, int fudge);
+void RCS_check_tag (char *tag);
+void freercsnode (RCSNode ** rnodep);
+#else
+List *RCS_parsefiles ();
+RCSNode *RCS_parse ();
+char *RCS_head ();
+char *RCS_getversion ();
+char *RCS_magicrev ();
+int RCS_isbranch ();
+char *RCS_whatbranch ();
+char *RCS_gettag ();
+char *RCS_getdate ();
+char *RCS_check_kflag ();
+void RCS_check_tag ();
+time_t RCS_getrevtime ();
+RCSNode *RCS_parsercsfile ();
+int RCS_datecmp ();
+void freercsnode ();
+#endif /* __STDC__ */
diff --git a/gnu/usr.bin/cvs/cvs/recurse.c b/gnu/usr.bin/cvs/cvs/recurse.c
new file mode 100644
index 0000000..82301d5
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/recurse.c
@@ -0,0 +1,535 @@
+/*
+ * 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.3 kit.
+ *
+ * General recursion handler
+ *
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static char rcsid[] = "@(#)recurse.c 1.22 92/04/10";
+#endif
+
+#if __STDC__
+static int do_dir_proc (Node * p);
+static int do_file_proc (Node * p);
+static void addlist (List ** listp, char *key);
+#else
+static int do_file_proc ();
+static int do_dir_proc ();
+static void addlist ();
+#endif /* __STDC__ */
+
+
+/*
+ * Local static versions eliminates the need for globals
+ */
+static int (*fileproc) ();
+static int (*filesdoneproc) ();
+static Dtype (*direntproc) ();
+static int (*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;
+static List *dirlist = NULL;
+
+/*
+ * Called to start a recursive command Command line arguments are processed
+ * if present, otherwise the local directory is processed.
+ */
+int
+start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
+ argc, argv, local, which, aflag, readlock,
+ update_preload, dosrcs)
+ int (*fileproc) ();
+ int (*filesdoneproc) ();
+ Dtype (*direntproc) ();
+ int (*dirleaveproc) ();
+ int argc;
+ char *argv[];
+ int local;
+ int which;
+ int aflag;
+ int readlock;
+ char *update_preload;
+ int dosrcs;
+{
+ int i, err = 0;
+ Dtype flags;
+
+ 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)
+ dellist (&entries);
+ if (srcfiles)
+ dellist (&srcfiles);
+ if (filelist)
+ dellist (&filelist);
+ 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) && !isdir (OCVSADM))
+ dirlist = Find_Dirs ((char *) NULL, W_LOCAL);
+ else
+ addlist (&dirlist, ".");
+
+ err += do_recursion (fileproc, filesdoneproc, direntproc,
+ dirleaveproc, flags, which, aflag,
+ readlock, dosrcs);
+ }
+ else
+ {
+
+ /*
+ * 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
+ */
+
+ /* look for args with /-s in them */
+ for (i = 0; i < argc; i++)
+ if (index (argv[i], '/') != NULL)
+ break;
+
+ /* if we didn't find any hard one's, do it the easy way */
+ if (i == argc)
+ {
+ /* set up the lists */
+ for (i = 0; i < argc; i++)
+ {
+ if (isdir (argv[i]))
+ addlist (&dirlist, argv[i]);
+ else
+ {
+ if (isdir (CVSADM) || isdir (OCVSADM))
+ {
+ char *repos;
+ char tmp[PATH_MAX];
+
+ repos = Name_Repository ((char *) NULL, update_dir);
+ (void) sprintf (tmp, "%s/%s", repos, argv[i]);
+ if (isdir (tmp))
+ addlist (&dirlist, argv[i]);
+ else
+ addlist (&filelist, argv[i]);
+ free (repos);
+ }
+ else
+ addlist (&filelist, argv[i]);
+ }
+ }
+
+ /* we aren't recursive if no directories were specified */
+ if (dirlist == NULL)
+ local = 1;
+
+ /* process the lists */
+ err += do_recursion (fileproc, filesdoneproc, direntproc,
+ dirleaveproc, flags, which, aflag,
+ readlock, dosrcs);
+ }
+ /* otherwise - do it the hard way */
+ else
+ {
+ char *cp;
+ char *dir = (char *) NULL;
+ char *comp = (char *) NULL;
+ char *oldupdate = (char *) NULL;
+ char savewd[PATH_MAX];
+
+ if (getwd (savewd) == NULL)
+ error (1, 0, "could not get working directory: %s", savewd);
+
+ for (i = 0; i < argc; i++)
+ {
+ /* split the arg into the dir and component parts */
+ dir = xstrdup (argv[i]);
+ if ((cp = rindex (dir, '/')) != NULL)
+ {
+ *cp = '\0';
+ comp = xstrdup (cp + 1);
+ oldupdate = xstrdup (update_dir);
+ if (update_dir[0] != '\0')
+ (void) strcat (update_dir, "/");
+ (void) strcat (update_dir, dir);
+ }
+ else
+ {
+ comp = xstrdup (dir);
+ if (dir)
+ free (dir);
+ dir = (char *) NULL;
+ }
+
+ /* chdir to the appropriate place if necessary */
+ if (dir && chdir (dir) < 0)
+ error (1, errno, "could not chdir to %s", dir);
+
+ /* set up the list */
+ if (isdir (comp))
+ addlist (&dirlist, comp);
+ else
+ {
+ if (isdir (CVSADM) || isdir (OCVSADM))
+ {
+ char *repos;
+ char tmp[PATH_MAX];
+
+ repos = Name_Repository ((char *) NULL, update_dir);
+ (void) sprintf (tmp, "%s/%s", repos, comp);
+ if (isdir (tmp))
+ addlist (&dirlist, comp);
+ else
+ addlist (&filelist, comp);
+ free (repos);
+ }
+ else
+ addlist (&filelist, comp);
+ }
+
+ /* do the recursion */
+ err += do_recursion (fileproc, filesdoneproc, direntproc,
+ dirleaveproc, flags, which,
+ aflag, readlock, dosrcs);
+
+ /* chdir back and fix update_dir if necessary */
+ if (dir && chdir (savewd) < 0)
+ error (1, errno, "could not chdir to %s", dir);
+ if (oldupdate)
+ {
+ (void) strcpy (update_dir, oldupdate);
+ free (oldupdate);
+ }
+
+ }
+ if (dir)
+ free (dir);
+ if (comp)
+ free (comp);
+ }
+ }
+ 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)
+ int (*xfileproc) ();
+ int (*xfilesdoneproc) ();
+ Dtype (*xdirentproc) ();
+ int (*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;
+
+ /*
+ * Fill in repository with the current repository
+ */
+ if (which & W_LOCAL)
+ {
+ if (isdir (CVSADM) || isdir (OCVSADM))
+ 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 = ParseEntries (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);
+
+ /* unlock it */
+ if (readlock)
+ Lock_Cleanup ();
+
+ /* clean up */
+ dellist (&filelist);
+ dellist (&srcfiles);
+ dellist (&entries);
+ }
+
+ /* 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);
+#ifdef notdef
+ else if (dirleaveproc != NULL)
+ err += dirleaveproc(".", err, ".");
+#endif
+ dellist (&dirlist);
+
+ /* free the saved copy of the pointer if necessary */
+ if (srepository)
+ {
+ (void) 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)
+ Node *p;
+{
+ 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)
+ Node *p;
+{
+ char *dir = p->key;
+ char savewd[PATH_MAX];
+ char newrepos[PATH_MAX];
+ List *sdirlist;
+ char *srepository;
+ char *cp;
+ Dtype dir_return = R_PROCESS;
+ int stripped_dot = 0;
+ int err = 0;
+
+ /* 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 (getwd (savewd) == NULL)
+ error (1, 0, "could not get working directory: %s", savewd);
+ 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 (chdir (savewd) < 0)
+ error (1, errno, "could not chdir to %s", savewd);
+ dirlist = sdirlist;
+ repository = srepository;
+ }
+
+ /* put back update_dir */
+ if ((cp = rindex (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);
+ (void) addnode (*listp, p);
+}
diff --git a/gnu/usr.bin/cvs/cvs/release.c b/gnu/usr.bin/cvs/cvs/release.c
new file mode 100644
index 0000000..e2a941a
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/release.c
@@ -0,0 +1,223 @@
+/*
+ * 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 char rcsid[] = "@(#)release.c 1.21 92/02/29";
+#endif
+
+#if __STDC__
+static void release_delete (char *dir);
+#else
+static void release_delete ();
+#endif /* __STDC__ */
+
+static char *release_usage[] =
+{
+ "Usage: %s %s [-d] modules...\n",
+ "\t-Q\tReally quiet.\n",
+ "\t-d\tDelete the given directory.\n",
+ "\t-q\tSomewhat quiet.\n",
+ NULL
+};
+
+static short delete;
+
+int
+release (argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *fp;
+ register int i, c;
+ register char *cp;
+ int margc;
+ DBM *db;
+ datum key, val;
+ char *repository, *srepos;
+ char **margv, *modargv[MAXFILEPERDIR], line[PATH_MAX];
+
+ if (argc == -1)
+ usage (release_usage);
+ optind = 1;
+ while ((c = gnu_getopt (argc, argv, "Qdq")) != -1)
+ {
+ switch (c)
+ {
+ case 'Q':
+ really_quiet = 1;
+ /* FALL THROUGH */
+ case 'q':
+ quiet = 1;
+ break;
+ case 'd':
+ delete++;
+ break;
+ case '?':
+ default:
+ usage (release_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!(db = open_module ()))
+ return (1);
+ for (i = 0; i < argc; i++)
+ {
+
+ /*
+ * 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 (argv[i]))
+ {
+ if (chdir (argv[i]) < 0)
+ {
+ if (!really_quiet)
+ error (0, 0, "can't chdir to: %s", argv[i]);
+ continue;
+ }
+ if (!isdir (CVSADM) && !isdir (OCVSADM))
+ {
+ if (!really_quiet)
+ error (0, 0, "no repository module: %s", argv[i]);
+ continue;
+ }
+ }
+ else
+ {
+ if (!really_quiet)
+ error (0, 0, "no such directory/module: %s", argv[i]);
+ continue;
+ }
+
+ repository = Name_Repository ((char *) NULL, (char *) NULL);
+ srepos = Short_Repository (repository);
+
+ /* grab module entry from database and check against short repos */
+ key.dptr = argv[i];
+ key.dsize = strlen (key.dptr);
+ val = dbm_fetch (db, key);
+ if (!val.dptr)
+ {
+ error (0, 0, "no such module name: %s", argv[i]);
+ continue;
+ }
+ val.dptr[val.dsize] = '\0';
+ if ((cp = index (val.dptr, '#')) != NULL) /* Strip out a comment */
+ {
+ do
+ {
+ *cp-- = '\0';
+ } while (isspace (*cp));
+ }
+ (void) sprintf (line, "%s %s", key.dptr, val.dptr);
+ line2argv (&margc, modargv, line);
+ margv = modargv;
+
+ optind = 1;
+ while (gnu_getopt (margc, margv, CVSMODULE_OPTS) != -1)
+ /* do nothing */ ;
+ margc -= optind;
+ margv += optind;
+
+ if (margc < 1)
+ {
+ error (0, 0, "modules file missing directory for key %s value %s",
+ key.dptr, val.dptr);
+ continue;
+ }
+ if (strcmp (*margv, srepos))
+ {
+ error (0, 0, "repository mismatch: module[%s], here[%s]",
+ *margv, srepos);
+ free (repository);
+ continue;
+ }
+
+ if (!really_quiet)
+ {
+
+ /*
+ * Now see if there is any reason not to allow a "Release" This
+ * is "popen()" instead of "Popen()" since we don't want "-n" to
+ * stop it.
+ */
+#ifdef FREEBSD_DEVELOPER
+ fp = popen ("ncvs -n -q update", "r");
+#else
+ fp = popen ("cvs -n -q update", "r");
+#endif /* FREEBSD_DEVELOPER */
+ c = 0;
+ while (fgets (line, sizeof (line), fp))
+ {
+ if (index ("MARCZ", *line))
+ c++;
+ (void) printf (line);
+ }
+ (void) pclose (fp);
+ (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) " : "", argv[i]);
+ c = !yesno ();
+ if (c) /* "No" */
+ {
+ (void) fprintf (stderr, "** `%s' aborted by user choice.\n",
+ command_name);
+ free (repository);
+ continue;
+ }
+ }
+
+ /*
+ * So, we've passed all the tests, go ahead and release it. First,
+ * log the release, then attempt to delete it.
+ */
+ history_write ('F', argv[i], "", argv[i], ""); /* F == Free */
+ free (repository);
+
+ if (delete)
+ release_delete (argv[i]);
+ }
+ close_module (db);
+ return (0);
+}
+
+/* We want to "rm -r" the repository, 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;
+ }
+ run_setup ("%s -r", 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..5cce883
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/remove.c
@@ -0,0 +1,176 @@
+/*
+ * 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.3 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 char rcsid[] = "@(#)remove.c 1.34 92/04/10";
+#endif
+
+#if __STDC__
+static int remove_fileproc (char *file, char *update_dir,
+ char *repository, List *entries,
+ List *srcfiles);
+static Dtype remove_dirproc (char *dir, char *repos, char *update_dir);
+#else
+static Dtype remove_dirproc ();
+static int remove_fileproc ();
+#endif
+
+static int local;
+static int removed_files;
+static int auto_removed_files;
+
+static char *remove_usage[] =
+{
+ "Usage: %s %s [-lR] [files...]\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 = gnu_getopt (argc, argv, "lR")) != -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case '?':
+ default:
+ usage (remove_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* 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);
+
+ if (removed_files)
+ error (0, 0, "use '%s commit' to remove %s permanently", program_name,
+ (removed_files == 1) ? "this file" : "these files");
+ else
+ if (!auto_removed_files)
+ error (0, 0, "no files removed; use `%s' to remove the file first",
+ 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;
+
+ vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
+ file, 0, 0, entries, srcfiles);
+
+ if (vers->ts_user != NULL)
+ {
+ freevers_ts (&vers);
+ return (0);
+ }
+
+ if (vers->vn_user == NULL)
+ {
+ if (!quiet)
+ error (0, 0, "nothing known about %s", file);
+ freevers_ts (&vers);
+ return (0);
+ }
+
+ 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 ,p and ,t file for it and scratch it from the
+ * entries file.
+ */
+ Scratch_Entry (entries, file);
+ (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_OPT);
+ (void) unlink_file (fname);
+ (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
+ (void) unlink_file (fname);
+ if (!quiet)
+ error (0, 0, "removed `%s'.", file);
+ auto_removed_files++;
+ }
+ else if (vers->vn_user[0] == '-')
+ {
+ freevers_ts (&vers);
+ return (0);
+ }
+ 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);
+ if (!quiet)
+ {
+ error (0, 0, "scheduling %s for removal", file);
+ removed_files++;
+ }
+ }
+
+ 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..43a9dfe
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/repos.c
@@ -0,0 +1,169 @@
+/*
+ * 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.3 kit.
+ *
+ * Name of Repository
+ *
+ * Determine the name of the RCS repository and sets "Repository" accordingly.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static char rcsid[] = "@(#)repos.c 1.28 92/03/31";
+#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 ocvsadm[PATH_MAX];
+ char *cp;
+ int has_cvsadm = 0, has_ocvsadm = 0;
+
+ if (update_dir && *update_dir)
+ xupdate_dir = update_dir;
+ else
+ xupdate_dir = ".";
+
+ if (dir != NULL)
+ {
+ (void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
+ (void) sprintf (ocvsadm, "%s/%s", dir, OCVSADM);
+ }
+ else
+ {
+ (void) strcpy (cvsadm, CVSADM);
+ (void) strcpy (ocvsadm, OCVSADM);
+ }
+
+ /* sanity checks */
+ if (!(has_cvsadm = isdir (cvsadm)) && !(has_ocvsadm = isdir (ocvsadm)))
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (1, 0, "there is no version here; do '%s checkout' first",
+ program_name);
+ }
+
+ if (has_ocvsadm)
+ {
+ if (has_cvsadm)
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (1, 0, "error: both `%s' and `%s' exist; I give up",
+ CVSADM, OCVSADM);
+ }
+ if (rename (ocvsadm, cvsadm) < 0)
+ {
+ error (0, 0, "in directory %s:", xupdate_dir);
+ error (1, errno, "cannot rename `%s' to `%s'; I give up",
+ OCVSADM, CVSADM);
+ }
+
+ /*
+ * We have converted the old CVS.adm directory to the new CVS
+ * directory. Now, convert the Entries file to the new format, if
+ * necessary.
+ */
+ check_entries (dir);
+ }
+
+ 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 = rindex (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 (repos[0] != '/')
+ {
+ 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);
+ }
+ if (!isdir (repos))
+ {
+ 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 */
+ if (strncmp (CVSroot, repository, strlen (CVSroot)) == 0)
+ return (repository + strlen (CVSroot) + 1);
+ else
+ return (repository);
+}
diff --git a/gnu/usr.bin/cvs/cvs/rtag.c b/gnu/usr.bin/cvs/cvs/rtag.c
new file mode 100644
index 0000000..a53e8c7
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/rtag.c
@@ -0,0 +1,403 @@
+/*
+ * 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.3 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 char rcsid[] = "@(#)rtag.c 1.57 92/04/10";
+#endif
+
+#if __STDC__
+static Dtype rtag_dirproc (char *dir, char *repos, char *update_dir);
+static int rtag_fileproc (char *file, char *update_dir,
+ char *repository, List * entries,
+ List * srcfiles);
+static int rtag_proc (int *pargc, char *argv[], char *xwhere,
+ char *mwhere, char *mfile, int shorten,
+ int local_specified, char *mname, char *msg);
+static int rtag_delete (RCSNode *rcsfile);
+#else
+static int rtag_proc ();
+static int rtag_fileproc ();
+static Dtype rtag_dirproc ();
+static int rtag_delete ();
+#endif /* __STDC__ */
+
+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 char *rtag_usage[] =
+{
+ "Usage: %s %s [-QaflRnq] [-b] [-d] [-r tag|-D date] tag modules...\n",
+ "\t-Q\tReally quiet.\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-q\tSomewhat quiet.\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",
+ 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 = gnu_getopt (argc, argv, "anfQqlRdbr:D:")) != -1)
+ {
+ switch (c)
+ {
+ case 'a':
+ attic_too = 1;
+ break;
+ case 'n':
+ run_module_prog = 0;
+ break;
+ case 'Q':
+ really_quiet = 1;
+ /* FALL THROUGH */
+ case 'q':
+ quiet = 1;
+ 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 '?':
+ 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);
+
+ 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 = rindex (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;
+
+ /* start the recursion processor */
+ err = start_recursion (rtag_fileproc, (int (*) ()) NULL, rtag_dirproc,
+ (int (*) ()) NULL, *pargc - 1, argv + 1, local,
+ which, 0, 1, where, 1);
+
+ return (err);
+}
+
+/*
+ * 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);
+ 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;
+ run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, 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.
+ */
+ oversion = RCS_getversion (rcsfile, symtag, (char *) 0, 1);
+ if (oversion != NULL)
+ {
+ if (strcmp (version, oversion) == 0)
+ {
+ free (version);
+ free (oversion);
+ return (0);
+ }
+ free (oversion);
+ }
+ rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
+ run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, symtag, rev);
+ }
+ run_arg (rcsfile->path);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
+ {
+ if (!quiet)
+ error (0, 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 *) 0, 1);
+ if (version == NULL)
+ return (0);
+ free (version);
+ }
+
+ version = RCS_getversion (rcsfile, symtag, (char *) 0, 1);
+ if (version == NULL)
+ return (0);
+ free (version);
+
+ run_setup ("%s%s -q -N%s", Rcsbin, RCS, symtag);
+ run_arg (rcsfile->path);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL)) != 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/status.c b/gnu/usr.bin/cvs/cvs/status.c
new file mode 100644
index 0000000..9749740
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/status.c
@@ -0,0 +1,230 @@
+/*
+ * 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.3 kit.
+ *
+ * Status Information
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static char rcsid[] = "@(#)status.c 1.48 92/03/31";
+#endif
+
+#if __STDC__
+static Dtype status_dirproc (char *dir, char *repos, char *update_dir);
+static int status_fileproc (char *file, char *update_dir,
+ char *repository, List * entries,
+ List * srcfiles);
+static int tag_list_proc (Node * p);
+#else
+static int tag_list_proc ();
+static int status_fileproc ();
+static Dtype status_dirproc ();
+#endif /* __STDC__ */
+
+static int local = 0;
+static int long_format = 0;
+
+static char *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 = gnu_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;
+
+ /* start the recursion processor */
+ err = start_recursion (status_fileproc, (int (*) ()) NULL, status_dirproc,
+ (int (*) ()) NULL, argc, argv, local,
+ W_LOCAL, 0, 1, (char *) NULL, 1);
+
+ 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);
+ switch (status)
+ {
+ case T_UNKNOWN:
+ sstat = "Unknown";
+ break;
+ case T_CHECKOUT:
+ sstat = "Needs Checkout";
+ break;
+ case T_CONFLICT:
+ sstat = "Unresolved Conflict";
+ break;
+ case T_ADDED:
+ sstat = "Locally Added";
+ break;
+ case T_REMOVED:
+ sstat = "Locally Removed";
+ break;
+ case T_MODIFIED:
+ 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: %-17.17s\tStatus: %s\n\n", file, sstat);
+
+ if (vers->vn_user == NULL)
+ (void) printf (" Version:\t\tNo entry for %s\n", file);
+ else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
+ (void) printf (" Version:\t\tNew file!\n");
+ else
+ (void) printf (" Version:\t\t%s\t%s\n", vers->vn_user,
+ &vers->ts_rcs[25]);
+
+ if (vers->vn_rcs == NULL)
+ (void) printf (" RCS Version:\tNo revision control file\n");
+ else
+ (void) printf (" RCS Version:\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
+ (void) printf (" Sticky Tag:\t\t%s (%s: %s)\n",
+ edata->tag, numdots (vers->vn_rcs) % 2 ?
+ "revision" : "branch", vers->vn_rcs);
+ }
+ }
+ else
+ (void) printf (" Sticky Tag:\t\t(none)\n");
+
+ if (edata->date)
+ (void) printf (" Sticky Date:\t%s\n", edata->date);
+ else
+ (void) printf (" Sticky Date:\t(none)\n");
+
+ if (edata->options && edata->options[0])
+ (void) printf (" Sticky Options:\t%s\n", edata->options);
+ else
+ (void) printf (" Sticky Options:\t(none)\n");
+
+ if (long_format && vers->srcfile)
+ {
+ (void) printf ("\n Existing Tags:\n");
+ if (vers->srcfile->symbols)
+ (void) walklist (vers->srcfile->symbols, tag_list_proc);
+ 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)
+ Node *p;
+{
+ (void) printf ("\t%-25.25s\t(%s: %s)\n", p->key,
+ numdots (p->data) % 2 ? "revision" : "branch",
+ 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..71a8c46
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/tag.c
@@ -0,0 +1,263 @@
+/*
+ * 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.3 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 char rcsid[] = "@(#)tag.c 1.56 92/03/31";
+#endif
+
+#if __STDC__
+static Dtype tag_dirproc (char *dir, char *repos, char *update_dir);
+static int tag_fileproc (char *file, char *update_dir,
+ char *repository, List * entries,
+ List * srcfiles);
+#else
+static int tag_fileproc ();
+static Dtype tag_dirproc ();
+#endif /* __STDC__ */
+
+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 char *tag_usage[] =
+{
+ "Usage: %s %s [-QlRq] [-b] [-d] tag [files...]\n",
+ "\t-Q\tReally quiet.\n",
+ "\t-l\tLocal directory only, not recursive.\n",
+ "\t-R\tProcess directories recursively.\n",
+ "\t-q\tSomewhat quiet.\n",
+ "\t-d\tDelete the given Tag.\n",
+ "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\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 = gnu_getopt (argc, argv, "QqlRdb")) != -1)
+ {
+ switch (c)
+ {
+ case 'Q':
+ really_quiet = 1;
+ /* FALL THROUGH */
+ case 'q':
+ quiet = 1;
+ break;
+ case 'l':
+ local = 1;
+ break;
+ case 'R':
+ local = 0;
+ break;
+ case 'd':
+ delete = 1;
+ break;
+ case 'b':
+ branch_mode = 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);
+
+ /* start the recursion processor */
+ err = start_recursion (tag_fileproc, (int (*) ()) NULL, tag_dirproc,
+ (int (*) ()) NULL, argc, argv, local,
+ W_LOCAL, 0, 1, (char *) NULL, 1);
+ return (err);
+}
+
+/*
+ * 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 *rev;
+ Vers_TS *vers;
+ int retcode = 0;
+
+ vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL,
+ file, 0, 0, entries, srcfiles);
+
+ 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);
+ if (version == NULL || vers->srcfile == NULL)
+ {
+ freevers_ts (&vers);
+ return (0);
+ }
+ free (version);
+
+ run_setup ("%s%s -q -N%s", Rcsbin, RCS, symtag);
+ run_arg (vers->srcfile->path);
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL)) != 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.
+ */
+ version = vers->vn_user;
+ 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.
+ */
+ oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1);
+ if (oversion != NULL)
+ {
+ if (strcmp (version, oversion) == 0)
+ {
+ free (oversion);
+ freevers_ts (&vers);
+ return (0);
+ }
+ free (oversion);
+ }
+ rev = branch_mode ? RCS_magicrev (vers->srcfile, version) : version;
+ run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, symtag, rev);
+ 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,
+ "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);
+ 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..d91ffdd
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/update.c
@@ -0,0 +1,1076 @@
+/*
+ * 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.3 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"
+
+#ifndef lint
+static char rcsid[] = "@(#)update.c 1.83 92/04/10";
+#endif
+
+#if __STDC__
+static int checkout_file (char *file, char *repository, List *entries,
+ List *srcfiles, Vers_TS *vers_ts, char *update_dir);
+static int isemptydir (char *dir);
+static int merge_file (char *file, char *repository, List *entries,
+ Vers_TS *vers, char *update_dir);
+static int scratch_file (char *file, char *repository, List * entries,
+ char *update_dir);
+static Dtype update_dirent_proc (char *dir, char *repository, char *update_dir);
+static int update_dirleave_proc (char *dir, int err, char *update_dir);
+static int update_file_proc (char *file, char *update_dir, char *repository,
+ List * entries, List * srcfiles);
+static int update_filesdone_proc (int err, char *repository, char *update_dir);
+static int write_letter (char *file, int letter, char *update_dir);
+static void ignore_files (List * ilist, char *update_dir);
+static void join_file (char *file, List *srcfiles, Vers_TS *vers_ts,
+ char *update_dir);
+#else
+static int update_file_proc ();
+static int update_filesdone_proc ();
+static Dtype update_dirent_proc ();
+static int update_dirleave_proc ();
+static int isemptydir ();
+static int scratch_file ();
+static int checkout_file ();
+static int write_letter ();
+static int merge_file ();
+static void ignore_files ();
+static void join_file ();
+#endif /* __STDC__ */
+
+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 char *K_flag;
+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;
+static List *ignlist = (List *) NULL;
+
+static char *update_usage[] =
+{
+ "Usage:\n %s %s [-APQdflRpq] [-k kopt] [-r rev|-D date] [-j rev] [-I ign] [files...]\n",
+ "\t-A\tReset any sticky tags/date/kopts.\n",
+ "\t-P\tPrune empty directories.\n",
+ "\t-Q\tReally quiet.\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-q\tSomewhat quiet.\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-K key\tUse RCS key -K option on checkout.\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 ();
+
+ /* parse the args */
+ optind = 1;
+ while ((c = gnu_getopt (argc, argv, "ApPflRQqdk:r:D:j:I:K:")) != -1)
+ {
+ switch (c)
+ {
+ case 'A':
+ aflag = 1;
+ break;
+ case 'I':
+ ign_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':
+ really_quiet = 1;
+ /* FALL THROUGH */
+ case 'q':
+ quiet = 1;
+ 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 'K':
+ K_flag = optarg;
+ break;
+ case '?':
+ default:
+ usage (update_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef FREEBSD_DEVELOPER
+ if (!K_flag && freebsd) {
+ /* XXX Note: The leading -K is not needed, it gets added later! */
+ K_flag = "eAuthor,eDate,eHeader,eId,eLocker,eLog,eRCSfile,eRevision,eSource,eState,iFreeBSD";
+ }
+#endif /* FREEBSD_DEVELOPER */
+
+ /*
+ * 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)
+ (void) unlink_file (CVSADM_ENTSTAT);
+
+ /* keep the CVS/Tag file current with the specified arguments */
+ if (aflag || tag || date)
+ WriteTag ((char *) NULL, tag, date);
+ }
+
+ /* 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)
+ 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,
+ K_flag, (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,
+ xK_flag, 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 *xK_flag;
+ 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;
+
+ K_flag = xK_flag;
+
+ /* setup the join support */
+ join_rev1 = xjoin_rev1;
+ join_rev2 = xjoin_rev2;
+ if (join_rev1 && (cp = index (join_rev1, ':')) != NULL)
+ {
+ *cp++ = '\0';
+ date_rev1 = Make_Date (cp);
+ }
+ else
+ date_rev1 = (char *) NULL;
+ if (join_rev2 && (cp = index (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);
+ 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);
+ 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 */
+ 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;
+ break;
+ case T_NEEDS_MERGE: /* needs merging */
+ retval = merge_file (file, repository, entries,
+ vers, update_dir);
+ break;
+ case T_MODIFIED: /* locally modified */
+ retval = write_letter (file, 'M', update_dir);
+ break;
+ case T_CHECKOUT: /* needs checkout */
+ retval = checkout_file (file, repository, entries, srcfiles,
+ vers, update_dir);
+ 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);
+ 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)
+ join_file (file, srcfiles, vers, update_dir);
+
+ /* 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);
+ return (retval);
+}
+
+/*
+ * update_filesdone_proc () is used
+ */
+/* ARGSUSED */
+static int
+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 */
+ if (strcmp (command_name, "export") == 0)
+ {
+ run_setup ("%s -fr", RM);
+ run_arg (CVSADM);
+ (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ }
+
+#ifdef DO_LINKS
+ {
+ char lnfile[PATH_MAX];
+ FILE *links;
+
+ sprintf(lnfile, "%s/SymLinks", repository);
+ links = fopen(lnfile, "r");
+ if (links) {
+ char from[PATH_MAX], to[PATH_MAX];
+
+ /* Read all the link pairs from the symlinks file */
+ while (fgets(to, PATH_MAX, links)) {
+ fgets(from, PATH_MAX, links);
+
+ /* Strip off the newlines */
+ to[strlen(to) - 1] = '\0';
+ from[strlen(from) - 1] = '\0';
+
+ /* Do it */
+ if (symlink(from, to) == -1) {
+ error (0, errno, "Unable to create symlink `%s'", to);
+ return 1;
+ }
+ else if (!quiet)
+ error (0, 0, "Creating symlink %s", to);
+ }
+ fclose(links);
+ }
+ }
+#endif
+
+ 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 (!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, 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);
+ (void) unlink_file (tmp);
+ }
+
+ /* keep the CVS/Tag file current with the specified arguments */
+ if (aflag || tag || date)
+ WriteTag (dir, tag, date);
+
+ /* 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 = rindex (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);
+ }
+
+ /* Clean up CVS admin dirs if we are export */
+ if (strcmp (command_name, "export") == 0)
+ {
+ run_setup ("%s -fr", RM);
+ run_arg (CVSADM);
+ (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ }
+
+ /* 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 direct *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 &&
+ strcmp (dp->d_name, OCVSADM) != 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;
+
+ /* 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);
+ }
+
+ run_setup ("%s%s -q -r%s %s %s%s", Rcsbin, RCS_CO, vers_ts->vn_rcs,
+ vers_ts->options, K_flag ? "-K" : "", K_flag ? K_flag : "");
+
+ /*
+ * 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);
+
+ if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
+ (pipeout ? (RUN_NORMAL|RUN_REALLY) : RUN_NORMAL))) == 0)
+ {
+ if (!pipeout)
+ {
+ Vers_TS *xvers_ts;
+
+ if (cvswrite == TRUE)
+ xchmod (file, 1);
+
+ /* 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;
+
+ 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';
+ Register (entries, file, xvers_ts->vn_rcs, xvers_ts->ts_user,
+ xvers_ts->options, xvers_ts->tag, xvers_ts->date);
+
+ /* 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);
+
+ if (!really_quiet)
+ {
+ 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);
+}
+
+/*
+ * 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;
+ char 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);
+
+ /* XXX - Do merge by hand instead of using rcsmerge, due to -k handling */
+ run_setup ("%s%s %s -r%s -r%s", Rcsbin, RCS_RCSMERGE, vers->options,
+ vers->vn_user, vers->vn_rcs);
+ run_arg (vers->srcfile->path);
+ status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ if (status != 0
+#ifdef HAVE_RCS5
+ && status != 1
+#endif
+ )
+ {
+ 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);
+ }
+ /* XXX - Might want to make sure that rcsmerge changed the file */
+ if (strcmp (vers->options, "-V4") == 0)
+ vers->options[0] = '\0';
+ Register (entries, file, vers->vn_rcs, vers->ts_rcs, vers->options,
+ vers->tag, vers->date);
+
+ /* 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);
+ }
+
+ /* possibly run GREP to see if there appear to be conflicts in the file */
+ run_setup ("%s -s", GREP);
+ run_arg (RCS_MERGE_PAT);
+ run_arg (file);
+ if (status == 1 ||
+ (retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) == 0)
+ {
+ 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
+join_file (file, srcfiles, vers, update_dir)
+ char *file;
+ List *srcfiles;
+ Vers_TS *vers;
+ char *update_dir;
+{
+ char user[PATH_MAX];
+ char backup[PATH_MAX];
+ char *rev, *baserev;
+ char *options;
+ int status;
+
+ /* determine if we need to do anything at all */
+ if (vers->vn_user == NULL || vers->srcfile == NULL ||
+ vers->srcfile->path == NULL)
+ {
+ return;
+ }
+
+ /* special handling when two revisions are specified */
+ if (join_rev1 && join_rev2)
+ {
+ rev = RCS_getversion (vers->srcfile, join_rev2, date_rev2, 1);
+ 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);
+ 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 = rindex (baserev, '.');
+ int len = (dot - baserev) + 1;
+
+ if (strncmp (baserev, rev, len) == 0)
+ return;
+ }
+ }
+ else
+ {
+ rev = RCS_getversion (vers->srcfile, join_rev1, date_rev1, 1);
+ 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 = rindex (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;
+ }
+
+ /* OK, so we have a revision and possibly a base revision; continue on */
+
+ /*
+ * 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 (*options == '\0')
+ options = "-kk"; /* to ignore keyword expansions */
+#endif
+
+ /* XXX - Do merge by hand instead of using rcsmerge, due to -k handling */
+ run_setup ("%s%s %s %s%s -r%s", Rcsbin, RCS_RCSMERGE, options,
+ baserev ? "-r" : "", baserev ? baserev : "", rev);
+ run_arg (vers->srcfile->path);
+ status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ if (status != 0
+#ifdef HAVE_RCS5
+ && status != 1
+#endif
+ )
+ {
+ error (0, status == -1 ? errno : 0,
+ "could not merge revision %s of %s", rev, user);
+ error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
+ user, backup);
+ rename_file (backup, file);
+ }
+ free (rev);
+ if (baserev)
+ free (baserev);
+ return;
+}
+
+/*
+ * 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 direct *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);
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ file = dp->d_name;
+ if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0)
+ continue;
+ if (findnode (ilist, file) != NULL)
+ continue;
+ if (lstat (file, &sb) != -1)
+ {
+ if (S_ISDIR (sb.st_mode))
+ continue;
+#ifdef S_IFLNK
+ if (S_ISLNK (sb.st_mode))
+ continue;
+#endif
+ }
+ if (ign_name (file))
+ continue;
+ (void) write_letter (file, '?', xdir);
+ }
+ (void) closedir (dirp);
+}
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..6ac2488
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/vers_ts.c
@@ -0,0 +1,224 @@
+/*
+ * 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.3 kit.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static char rcsid[] = "@(#)vers_ts.c 1.36 92/03/31";
+#endif
+
+extern char *ctime (); /* XXX - should use gmtime/asctime */
+
+/*
+ * 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));
+ bzero ((char *) vers_ts, 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);
+ 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
+ rcsdata = RCS_parse (user, repository);
+
+ if (rcsdata != NULL)
+ {
+ /* squirrel away the rcsdata pointer for others */
+ vers_ts->srcfile = rcsdata;
+
+ /* 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))
+ {
+ if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0)
+ vers_ts->vn_rcs = xstrdup (vers_ts->vn_user);
+ else
+ vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag,
+ vers_ts->date, force_tag_match);
+ }
+
+ /*
+ * 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;
+
+ 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)
+ vers_ts->ts_user = time_stamp (user);
+
+ return (vers_ts);
+}
+
+/*
+ * 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 (51); /* 51 = 2 ctime strings + NULL */
+ cp = ctime (&sb.st_ctime); /* copy in the create time */
+ cp[24] = ' ';
+ (void) strcpy (ts, cp);
+ cp = ctime (&sb.st_mtime); /* copy in the modify time */
+ cp[24] = '\0';
+ (void) strcat (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)->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);
+ free ((char *) *versp);
+ *versp = (Vers_TS *) NULL;
+}
diff --git a/gnu/usr.bin/cvs/cvs/version.c b/gnu/usr.bin/cvs/cvs/version.c
new file mode 100644
index 0000000..18a9d14
--- /dev/null
+++ b/gnu/usr.bin/cvs/cvs/version.c
@@ -0,0 +1,11 @@
+/*
+ * 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.3 kit.
+ *
+ * version.c - the CVS version number
+ */
+
+char *version_string = "\nConcurrent Versions System (CVS) 1.3\n";
diff --git a/gnu/usr.bin/cvs/doc/cvs.ms b/gnu/usr.bin/cvs/doc/cvs.ms
new file mode 100644
index 0000000..567179b
--- /dev/null
+++ b/gnu/usr.bin/cvs/doc/cvs.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/examples/commitinfo b/gnu/usr.bin/cvs/examples/commitinfo
new file mode 100644
index 0000000..bdb94b6
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/commitinfo
@@ -0,0 +1,21 @@
+#
+# commitinfo,v 1.2 1992/03/31 04:19:47 berliner 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. If a match 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.
+#
+^cvs checkforcvsid
+DEFAULT checkforid
diff --git a/gnu/usr.bin/cvs/examples/editinfo b/gnu/usr.bin/cvs/examples/editinfo
new file mode 100644
index 0000000..b454abd
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/editinfo
@@ -0,0 +1,30 @@
+#
+# editinfo,v 1.1 1992/03/21 06:49:39 berliner 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.
+#
+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..6339439
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/loginfo
@@ -0,0 +1,20 @@
+#
+# @(#)loginfo 1.5 92/03/31
+#
+# 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. 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 (ala printf). If
+# %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 "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/log.pl %s $CVSROOT/CVSROOT/commitlog
diff --git a/gnu/usr.bin/cvs/examples/modules b/gnu/usr.bin/cvs/examples/modules
new file mode 100644
index 0000000..893b47b
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/modules
@@ -0,0 +1,566 @@
+#
+# CVS Modules file for Prisma sources
+# @(#)modules 1.5 92/03/31
+#
+# 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.
+# -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 .
+kernel -a sys lang/adb sparcsim
+
+# CVSROOT support
+CVSROOT -i /usr/local/bin/mkmodules CVSROOT
+modules -i /usr/local/bin/mkmodules CVSROOT modules
+loginfo -i /usr/local/bin/mkmodules CVSROOT loginfo
+commitinfo -i /usr/local/bin/mkmodules CVSROOT commitinfo
+rcsinfo -i /usr/local/bin/mkmodules CVSROOT rcsinfo
+
+# 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..6d91455
--- /dev/null
+++ b/gnu/usr.bin/cvs/examples/rcsinfo
@@ -0,0 +1,18 @@
+#
+# rcsinfo,v 1.3 1992/04/10 18:59:14 berliner 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. If a match 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 /src/master/CVSROOT/rcstemplate
diff --git a/gnu/usr.bin/cvs/lib/Makefile b/gnu/usr.bin/cvs/lib/Makefile
new file mode 100644
index 0000000..5233869
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/Makefile
@@ -0,0 +1,13 @@
+LIB = cvs
+
+CFLAGS += -I${.CURDIR} -I${.CURDIR}/../cvs -DFTIME_MISSING -DHAVE_TIMEZONE
+
+SRCS = argmatch.c error.c getopt.c sighandle.c strippath.c stripslash.c yesno.c \
+ getdate.y fnmatch.c regex.c subr.c myndbm.c hash.c
+
+CLEANFILES+= getdate.c y.tab.h
+
+install:
+ @echo -n
+
+.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/cvs/lib/Makefile.in b/gnu/usr.bin/cvs/lib/Makefile.in
new file mode 100644
index 0000000..a8309f2
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/Makefile.in
@@ -0,0 +1,91 @@
+# Makefile for library files used by GNU CVS.
+# Do not use this makefile directly, but only from `../Makefile'.
+# Copyright (C) 1986, 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.
+
+# @(#)Makefile.in 1.12 92/03/31
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+@VPATH@
+
+SOURCES = argmatch.c \
+error.c getopt.c getopt1.c \
+sighandle.c \
+strippath.c stripslash.c yesno.c \
+getdate.y \
+hostname.c fnmatch.c ftruncate.c mkdir.c rename.c regex.c \
+strdup.c getwd.c alloca.c
+
+OBJECTS = argmatch.o \
+error.o getopt.o getopt1.o \
+sighandle.o \
+strippath.o stripslash.o yesno.o \
+getdate.o \
+@LIBOBJS@
+
+DISTFILES = Makefile.in getopt.h \
+fnmatch.h regex.h system.h wait.h $(SOURCES)
+
+xxx:
+ @cd ..; $(MAKE) all SUBDIRS=lib
+
+all: libcvs.a
+.PHONY: all
+
+install: all
+.PHONY: install
+
+tags: $(DISTFILES)
+ ctags $(DISTFILES)
+
+TAGS: $(DISTFILES)
+ etags $(DISTFILES)
+
+ls:
+ @echo $(DISTFILES)
+.PHONY: ls
+
+clean:
+ rm -f *.a *.o *.tab.c getdate.c
+.PHONY: clean
+
+distclean: clean
+ rm -f tags TAGS Makefile
+.PHONY: distclean
+
+realclean: distclean
+.PHONY: realclean
+
+dist:
+ ln $(DISTFILES) ../`cat ../.fname`/lib
+.PHONY: dist
+
+libcvs.a: $(OBJECTS)
+ $(AR) cr $@ $(OBJECTS)
+ -$(RANLIB) $@
+
+getdate.c: getdate.y
+ @echo expect 8 shift/reduce conflicts
+ $(YACC) $(srcdir)/getdate.y
+ -if test -f y.tab.c ; then mv y.tab.c getdate.c ; fi
+ -if test -f getdate.tab.c ; then mv getdate.tab.c getdate.c ; fi
+
+fnmatch.o: fnmatch.h
+getopt1.o: getopt.h
+regex.o: regex.h
+getwd.o: system.h
diff --git a/gnu/usr.bin/cvs/lib/alloca.c b/gnu/usr.bin/cvs/lib/alloca.c
new file mode 100644
index 0000000..d2a54b3
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/alloca.c
@@ -0,0 +1,191 @@
+/*
+ alloca -- (mostly) portable public-domain implementation -- D A Gwyn
+
+ last edit: 86/05/30 rms
+ include config.h, since on VMS it renames some symbols.
+ Use xmalloc instead of malloc.
+
+ 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.
+
+ It should work under any C implementation that uses an
+ actual procedure stack (as opposed to a linked list of
+ frames). 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.
+*/
+#ifndef lint
+static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */
+#endif
+
+#ifdef emacs
+#include "config.h"
+#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 __STDC__
+typedef void *pointer; /* generic pointer type */
+#else
+typedef char *pointer; /* generic pointer type */
+#endif
+
+#define NULL 0 /* null pointer constant */
+
+extern void free();
+extern pointer xmalloc();
+
+/*
+ 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 (/* void */)
+{
+ static char *addr = NULL; /* address of first
+ `dummy', once known */
+ auto char dummy; /* to get stack address */
+
+ if (addr == NULL)
+ { /* initial entry */
+ addr = &dummy;
+
+ find_stack_direction (); /* recurse once */
+ }
+ else /* second entry */
+ if (&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;
+
+/*
+ alloca( size ) returns 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.
+*/
+
+static header *last_alloca_header = NULL; /* -> last alloca header */
+
+pointer
+alloca (size) /* returns pointer to storage */
+ unsigned size; /* # bytes to allocate */
+{
+ auto char probe; /* probes stack depth: */
+ register char *depth = &probe;
+
+#if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* unknown growth direction */
+ find_stack_direction ();
+#endif
+
+ /* Reclaim garbage, defined as all alloca()ed 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 = xmalloc (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));
+ }
+}
+
diff --git a/gnu/usr.bin/cvs/lib/argmatch.c b/gnu/usr.bin/cvs/lib/argmatch.c
new file mode 100644
index 0000000..3f765fe
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/argmatch.c
@@ -0,0 +1,83 @@
+/* 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> */
+
+#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. */
+ 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, "%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/dup2.c b/gnu/usr.bin/cvs/lib/dup2.c
new file mode 100644
index 0000000..0bd3aca
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/dup2.c
@@ -0,0 +1,36 @@
+/*
+ dup2 -- 7th Edition UNIX system call emulation for UNIX System V
+
+ last edit: 11-Feb-1987 D A Gwyn
+*/
+
+#include <errno.h>
+#include <fcntl.h>
+
+extern int close(), fcntl();
+
+int
+dup2( oldfd, newfd )
+ int oldfd; /* already-open file descriptor */
+ int newfd; /* desired duplicate descriptor */
+{
+ register int ret; /* for fcntl() return value */
+ register int save; /* for saving entry errno */
+
+ if ( oldfd == newfd )
+ return oldfd; /* be careful not to close() */
+
+ save = errno; /* save entry errno */
+ (void) close( newfd ); /* in case newfd is open */
+ /* (may have just clobbered the original errno value) */
+
+ ret = fcntl( oldfd, F_DUPFD, newfd ); /* dupe it */
+
+ if ( ret >= 0 )
+ errno = save; /* restore entry errno */
+ else /* fcntl() returned error */
+ if ( errno == EINVAL )
+ errno = EBADF; /* we think of everything */
+
+ return ret; /* return file descriptor */
+}
diff --git a/gnu/usr.bin/cvs/lib/error.c b/gnu/usr.bin/cvs/lib/error.c
new file mode 100644
index 0000000..fadb1c5
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/error.c
@@ -0,0 +1,193 @@
+/* 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 */
+
+#ifndef lint
+static char rcsid[] = "@(#)error.c 1.9 92/03/31";
+#endif /* not lint */
+
+#include <stdio.h>
+
+/* turn on CVS support by default, since this is the CVS distribution */
+#define CVS_SUPPORT
+
+#ifdef CVS_SUPPORT
+#if __STDC__
+void Lock_Cleanup(void);
+#else
+void Lock_Cleanup();
+#endif /* __STDC__ */
+#endif /* CVS_SUPPORT */
+
+#ifndef VPRINTF_MISSING
+
+#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
+
+#ifndef DOPRNT_MISSING
+#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
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else
+#if __STDC__
+void exit(int status);
+#else
+void exit ();
+#endif /* __STDC__ */
+#endif
+
+#ifdef STRERROR_MISSING
+static char *
+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";
+}
+#endif /* STRERROR_MISSING */
+
+/* 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 (VPRINTF_MISSING) && __STDC__
+error (int status, int errnum, char *message, ...)
+#else
+error (status, errnum, message, va_alist)
+ int status;
+ int errnum;
+ char *message;
+ va_dcl
+#endif
+{
+ extern char *program_name;
+#ifdef CVS_SUPPORT
+ extern char *command_name;
+#endif
+#ifndef VPRINTF_MISSING
+ va_list args;
+#endif
+
+#ifdef CVS_SUPPORT
+ if (command_name && *command_name)
+ if (status)
+ fprintf (stderr, "%s [%s aborted]: ", program_name, command_name);
+ else
+ fprintf (stderr, "%s %s: ", program_name, command_name);
+ else
+ fprintf (stderr, "%s: ", program_name);
+#else
+ fprintf (stderr, "%s: ", program_name);
+#endif
+#ifndef VPRINTF_MISSING
+ VA_START (args, message);
+ vfprintf (stderr, message, args);
+ va_end (args);
+#else
+#ifndef DOPRNT_MISSING
+ _doprnt (message, &args, stderr);
+#else
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+#endif
+ if (errnum)
+ fprintf (stderr, ": %s", strerror (errnum));
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ {
+#ifdef CVS_SUPPORT
+ Lock_Cleanup();
+#endif
+ exit (status);
+ }
+}
+
+#ifdef CVS_SUPPORT
+
+/* 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 (VPRINTF_MISSING) && __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;
+#ifndef VPRINTF_MISSING
+ va_list args;
+#endif
+
+ fprintf (fp, "%s: ", program_name);
+#ifndef VPRINTF_MISSING
+ VA_START (args, message);
+ vfprintf (fp, message, args);
+ va_end (args);
+#else
+#ifndef DOPRNT_MISSING
+ _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)
+ {
+#ifdef CVS_SUPPORT
+ Lock_Cleanup();
+#endif
+ exit (status);
+ }
+}
+
+#endif /* CVS_SUPPORT */
diff --git a/gnu/usr.bin/cvs/lib/fnmatch.c b/gnu/usr.bin/cvs/lib/fnmatch.c
new file mode 100644
index 0000000..50fa94c
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/fnmatch.c
@@ -0,0 +1,183 @@
+/* Copyright (C) 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. */
+
+/* Modified slightly by Brian Berliner <berliner@sun.com> for CVS use */
+
+/* IGNORE(@ */
+/* #include <ansidecl.h> */
+/* @) */
+#include <errno.h>
+#include <fnmatch.h>
+
+#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
+extern int errno;
+#endif
+
+#if !__STDC__
+#define const
+#endif
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+ it matches, nonzero if not. */
+int
+#if __STDC__
+fnmatch (const char *pattern, const char *string, int flags)
+#else
+fnmatch (pattern, string, flags)
+ char *pattern;
+ char *string;
+ int flags;
+#endif
+{
+ register const char *p = pattern, *n = string;
+ register char c;
+
+ if ((flags & ~__FNM_FLAGS) != 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ while ((c = *p++) != '\0')
+ {
+ switch (c)
+ {
+ case '?':
+ if (*n == '\0')
+ return FNM_NOMATCH;
+ else if ((flags & FNM_PATHNAME) && *n == '/')
+ return FNM_NOMATCH;
+ else if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+ break;
+
+ case '\\':
+ if (!(flags & FNM_NOESCAPE))
+ c = *p++;
+ if (*n != c)
+ return FNM_NOMATCH;
+ break;
+
+ case '*':
+ if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+
+ for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
+ if (((flags & FNM_PATHNAME) && *n == '/') ||
+ (c == '?' && *n == '\0'))
+ return FNM_NOMATCH;
+
+ if (c == '\0')
+ return 0;
+
+ {
+ char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
+ for (--p; *n != '\0'; ++n)
+ if ((c == '[' || *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_PATHNAME) && 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++;
+
+ if (c == '\0')
+ /* [ (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ c = *p++;
+
+ if ((flags & FNM_PATHNAME) && 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;
+ c = *p++;
+ }
+
+ if (*n >= cstart && *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 == '\\')
+ /* 1003.2d11 is unclear if this is right. %%% */
+ ++p;
+ }
+ if (not)
+ return FNM_NOMATCH;
+ }
+ break;
+
+ default:
+ if (c != *n)
+ return FNM_NOMATCH;
+ }
+
+ ++n;
+ }
+
+ if (*n == '\0')
+ return 0;
+
+ return FNM_NOMATCH;
+}
diff --git a/gnu/usr.bin/cvs/lib/fnmatch.h b/gnu/usr.bin/cvs/lib/fnmatch.h
new file mode 100644
index 0000000..a1e4f87
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/fnmatch.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 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. */
+
+#ifndef _FNMATCH_H
+
+#define _FNMATCH_H 1
+
+/* Bits set in the FLAGS argument to `fnmatch'. */
+#undef FNM_PATHNAME
+#define FNM_PATHNAME (1 << 0)/* No wildcard can ever match `/'. */
+#undef FNM_NOESCAPE
+#define FNM_NOESCAPE (1 << 1)/* Backslashes don't quote special chars. */
+#undef FNM_PERIOD
+#define FNM_PERIOD (1 << 2)/* Leading `.' is matched only explicitly. */
+#undef __FNM_FLAGS
+#define __FNM_FLAGS (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD)
+
+/* Value returned by `fnmatch' if STRING does not match PATTERN. */
+#undef FNM_NOMATCH
+#define FNM_NOMATCH 1
+
+/* Match STRING against the filename pattern PATTERN,
+ returning zero if it matches, FNM_NOMATCH if not. */
+#if __STDC__
+extern int fnmatch (const char *pattern, const char *string, int flags);
+#else
+extern int fnmatch ();
+#endif
+
+#endif /* fnmatch.h */
diff --git a/gnu/usr.bin/cvs/lib/ftruncate.c b/gnu/usr.bin/cvs/lib/ftruncate.c
new file mode 100644
index 0000000..17d263d
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/ftruncate.c
@@ -0,0 +1,72 @@
+/* ftruncate emulations that work on some System V's.
+ This file is in the public domain. */
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef F_CHSIZE
+int
+ftruncate (fd, length)
+ int fd;
+ off_t length;
+{
+ return fcntl (fd, F_CHSIZE, length);
+}
+#else
+#ifdef F_FREESP
+/* The following function was written by
+ kucharsk@Solbourne.com (William Kucharski) */
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+
+int
+ftruncate (fd, length)
+ int fd;
+ off_t length;
+{
+ 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), SEEK_SET) < 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, 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;
+}
+#else
+int
+ftruncate (fd, length)
+ int fd;
+ off_t length;
+{
+ return chsize (fd, length);
+}
+#endif
+#endif
diff --git a/gnu/usr.bin/cvs/lib/getdate.y b/gnu/usr.bin/cvs/lib/getdate.y
new file mode 100644
index 0000000..d010cb6
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/getdate.y
@@ -0,0 +1,889 @@
+%{
+/* 1.8
+** @(#)getdate.y 1.8 92/03/03
+**
+** 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 eight 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 */
+
+#include "system.h"
+#include <ctype.h>
+
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__)
+#ifdef __GNUC__
+#undef alloca /* might get redefined below */
+#endif
+#endif
+
+extern struct tm *localtime();
+
+#define yyparse getdate_yyparse
+#define yylex getdate_yylex
+#define yyerror getdate_yyerror
+
+#if !defined(lint) && !defined(SABER)
+static char RCS[] = "@(#)getdate.y 1.8 92/03/03";
+#endif /* !defined(lint) && !defined(SABER) */
+
+
+#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;
+ }
+ | 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) {
+ time_t date_part;
+
+ date_part= $1/10000;
+ yyHaveDate++;
+ yyDay= (date_part)%100;
+ yyMonth= (date_part/100)%100;
+ yyYear = date_part/10000;
+ }
+ 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 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 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 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 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 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 */
+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;
+ }
+ /* 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 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;
+}
+
+
+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);
+ }
+}
+
+
+time_t
+get_date(p, now)
+ char *p;
+ struct timeb *now;
+{
+ struct tm *tm;
+ struct timeb ftz;
+ time_t Start;
+ time_t tod;
+
+ yyInput = p;
+ if (now == NULL) {
+ now = &ftz;
+#if defined(FTIME_MISSING)
+ (void)time(&ftz.time);
+ /* Set the timezone global. */
+ tzset();
+#if defined(HAVE_TIMEZONE)
+ tm = localtime(&ftz.time);
+ ftz.timezone = tm->tm_gmtoff / 60;
+#else
+#if defined(timezone)
+ ftz.tzone = (int) timezone / 60;
+#else
+ ftz.timezone = (int) timezone / 60;
+#endif /* defined(timezone) */
+#endif /* defined(HAVE_TIMEZONE) */
+#else
+ (void)ftime(&ftz);
+#endif /* defined(FTIME_MISSING) */
+ }
+
+ tm = localtime(&now->time);
+ yyYear = tm->tm_year;
+ yyMonth = tm->tm_mon + 1;
+ yyDay = tm->tm_mday;
+#if defined(timezone)
+ yyTimezone = now->tzone;
+#else
+ yyTimezone = now->timezone;
+#endif /* defined(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 */
+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/getopt.c b/gnu/usr.bin/cvs/lib/getopt.c
new file mode 100644
index 0000000..c322fc2
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/getopt.c
@@ -0,0 +1,604 @@
+/* Getopt for GNU.
+ Copyright (C) 1987-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__
+#define const
+#endif
+
+/* 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 _POSIX_OPTION_ORDER 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[] = "@(#)getopt.c 1.7 92/03/31";
+#endif
+
+#include <stdio.h>
+
+#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
+#include <stdlib.h>
+#else /* STDC_HEADERS or __GNU_LIBRARY__ */
+char *getenv ();
+char *malloc ();
+#endif /* STDC_HEADERS or __GNU_LIBRARY__ */
+
+/* AIX requires this to be the first thing in the file. */
+#ifdef __GNUC__
+#if !defined(bsdi) && !defined(__386BSD__)
+#define alloca __builtin_alloca
+#endif
+#else /* not __GNUC__ */
+#ifdef sparc
+#include <alloca.h>
+#else
+#ifdef _AIX
+ #pragma alloca
+#else
+char *alloca ();
+#endif
+#endif /* sparc */
+#endif /* not __GNUC__ */
+
+#if defined(USG) || defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
+#include <string.h>
+#ifndef bcopy
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#endif
+#ifndef index
+#define index strchr
+#endif
+#else /* USG or STDC_HEADERS or __GNU_LIBRARY__ */
+#ifdef VMS
+#include <string.h>
+#else /* VMS */
+#include <strings.h>
+#endif /* VMS */
+/* Declaring bcopy causes errors on systems whose declarations are different.
+ If the declaration is omitted, everything works fine. */
+#endif /* USG or STDC_HEADERS or __GNU_LIBRARY__ */
+
+/* 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. */
+
+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;
+
+/* 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
+ _POSIX_OPTION_ORDER 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 POSIX_ME_HARDER, 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;
+
+/* Describe the long-named options requested by the application.
+ _GETOPT_LONG_OPTIONS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+ The field `has_arg' is 1 if the option takes an argument,
+ 2 if it takes an optional argument. */
+
+struct option
+{
+ char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+const struct option *_getopt_long_options;
+
+int _getopt_long_only = 0;
+
+/* Index in _GETOPT_LONG_OPTIONS of the long-named option actually found.
+ Only valid when a long-named option was found. */
+
+int option_index;
+
+/* 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. */
+
+ bcopy (&argv[first_nonopt], temp, nonopts_size);
+ bcopy (&argv[last_nonopt], &argv[first_nonopt],
+ (optind - last_nonopt) * sizeof (char *));
+ bcopy (temp, &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
+ otherwise. */
+
+int
+gnu_getopt (argc, argv, optstring)
+ int argc;
+ char **argv;
+ const char *optstring;
+{
+ 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 = 0;
+
+ /* 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 ("POSIX_ME_HARDER") != 0)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == 0 || *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 (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)
+ && (_getopt_long_options == 0
+ || argv[optind][0] != '+'
+ || argv[optind][1] == 0))
+ 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 (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)
+ && (_getopt_long_options == 0
+ || 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.
+ Start decoding its characters. */
+
+ nextchar = argv[optind] + 1;
+ }
+
+ if (_getopt_long_options != 0
+ && (argv[optind][0] == '+'
+ || (_getopt_long_only && argv[optind][0] == '-'))
+ )
+ {
+ const struct option *p;
+ char *s = nextchar;
+ int exact = 0;
+ int ambig = 0;
+ const struct option *pfound = 0;
+ int indfound = 0;
+
+ while (*s && *s != '=')
+ s++;
+
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = _getopt_long_options, 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 == 0)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != 0)
+ {
+ option_index = indfound;
+ optind++;
+ if (*s)
+ {
+ if (pfound->has_arg > 0)
+ optarg = s + 1;
+ else
+ {
+ 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
+ {
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ /* Can't find it as a long option. If this is getopt_long_only,
+ and the option starts with '-' and is a valid short
+ option, then interpret it as a short option. Otherwise it's
+ an error. */
+ if (_getopt_long_only == 0 || argv[optind][0] == '+' ||
+ index (optstring, *nextchar) == 0)
+ {
+ if (opterr != 0)
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == 0)
+ optind++;
+
+ if (temp == 0 || c == ':')
+ {
+ if (opterr != 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);
+ }
+ 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 = 0;
+ }
+ 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 != 0)
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = 0;
+ }
+ }
+ return c;
+ }
+}
+
+#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 = gnu_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..5f902de
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/getopt.h
@@ -0,0 +1,102 @@
+/* declarations for getopt
+ 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. */
+
+/* @(#)getopt.h 1.6 92/03/31 */
+
+/* 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;
+
+/* Describe the long-named options requested by the application.
+ _GETOPT_LONG_OPTIONS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ The field `has_arg' is:
+ 0 if the option does not take an argument,
+ 1 if the option requires an argument,
+ 2 if the option takes an optional argument.
+
+ If the field `flag' is nonzero, 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
+{
+ char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+#if __STDC__
+extern const struct option *_getopt_long_options;
+#else
+extern struct option *_getopt_long_options;
+#endif
+
+/* If nonzero, '-' can introduce long-named options.
+ Set by getopt_long_only. */
+
+extern int _getopt_long_only;
+
+/* The index in GETOPT_LONG_OPTIONS of the long-named option found.
+ Only valid when a long-named option has been found by the most
+ recent call to `getopt'. */
+
+extern int option_index;
+
+#if __STDC__
+int gnu_getopt (int argc, char **argv, const char *shortopts);
+int gnu_getopt_long (int argc, char **argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+int gnu_getopt_long_only (int argc, char **argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+#else
+int gnu_getopt ();
+int gnu_getopt_long ();
+int gnu_getopt_long_only ();
+#endif
diff --git a/gnu/usr.bin/cvs/lib/getopt1.c b/gnu/usr.bin/cvs/lib/getopt1.c
new file mode 100644
index 0000000..8606462
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/getopt1.c
@@ -0,0 +1,166 @@
+/* Getopt for GNU.
+ Copyright (C) 1987-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 "getopt.h"
+
+#if !__STDC__
+#define const
+#endif
+
+#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
+#include <stdlib.h>
+#else /* STDC_HEADERS or __GNU_LIBRARY__ */
+char *getenv ();
+#endif /* STDC_HEADERS or __GNU_LIBRARY__ */
+
+#if !defined (NULL)
+#define NULL 0
+#endif
+
+int
+gnu_getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char **argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ int val;
+
+ /* For strict POSIX compatibility, we must turn off long options. */
+ if (getenv ("POSIX_ME_HARDER") == 0)
+ _getopt_long_options = long_options;
+ val = gnu_getopt (argc, argv, options);
+ if (val == 0 && opt_index != NULL)
+ *opt_index = option_index;
+ return val;
+}
+
+/* Like getopt_long, but '-' as well as '+' can indicate a long option.
+ If an option that starts with '-' doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+gnu_getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char **argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ int val;
+
+ _getopt_long_options = long_options;
+ _getopt_long_only = 1;
+ val = gnu_getopt (argc, argv, options);
+ if (val == 0 && opt_index != NULL)
+ *opt_index = option_index;
+ return val;
+}
+
+
+#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;
+ char *name = '\0';
+ 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 '?':
+ 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/getwd.c b/gnu/usr.bin/cvs/lib/getwd.c
new file mode 100644
index 0000000..854feaf
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/getwd.c
@@ -0,0 +1,31 @@
+/* getwd.c -- get current working directory pathname
+ 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. */
+
+/* Some systems which include both getwd() and getcwd() have an implementation
+ of getwd() which is much faster than getcwd(). As a result, we use the
+ system's getwd() if it is available */
+
+#include "system.h"
+
+/* Get the current working directory into PATHNAME */
+
+char *
+getwd (pathname)
+ char *pathname;
+{
+ return (getcwd(pathname, PATH_MAX));
+}
diff --git a/gnu/usr.bin/cvs/lib/hash.c b/gnu/usr.bin/cvs/lib/hash.c
new file mode 100644
index 0000000..fb29497
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/hash.c
@@ -0,0 +1,338 @@
+/*
+ * 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.3 kit.
+ *
+ * Polk's hash list manager. So cool.
+ */
+
+#include "cvs.h"
+
+#ifndef lint
+static char rcsid[] = "@(#)hash.c 1.14 92/03/31";
+#endif
+
+/* global caches */
+static List *listcache = NULL;
+static Node *nodecache = NULL;
+
+#if __STDC__
+static void freenode_mem (Node * p);
+#else
+static void freenode_mem ();
+#endif /* __STDC__ */
+
+/* hash function */
+static int
+hashp (key)
+ char *key;
+{
+ register char *p;
+ register int n = 0;
+
+ for (p = key; *p; p++)
+ n += *p;
+
+ return (n % 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));
+ bzero ((char *) list, 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 */
+ bzero ((char *) p, 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
+ */
+Node *
+findnode (list, key)
+ List *list;
+ 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)
+ List *list;
+ int (*proc) ();
+{
+ 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);
+ return (err);
+}
+
+/*
+ * sort the elements of a list (in place)
+ */
+void
+sortlist (list, comp)
+ List *list;
+ int (*comp) ();
+{
+ 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;
+ }
+ }
+}
diff --git a/gnu/usr.bin/cvs/lib/hash.h b/gnu/usr.bin/cvs/lib/hash.h
new file mode 100644
index 0000000..54f227e
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/hash.h
@@ -0,0 +1,77 @@
+/* @(#)hash.h 1.18 92/03/31 */
+
+/*
+ * 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.3 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;
+
+struct entnode
+{
+ char *version;
+ char *timestamp;
+ char *options;
+ char *tag;
+ char *date;
+};
+typedef struct entnode Entnode;
+
+#if __STDC__
+List *getlist (void);
+Node *findnode (List * list, char *key);
+Node *getnode (void);
+int addnode (List * list, Node * p);
+int walklist (List * list, int (*proc) ());
+void dellist (List ** listp);
+void delnode (Node * p);
+void freenode (Node * p);
+void sortlist (List * list, int (*comp) ());
+#else
+List *getlist ();
+Node *findnode ();
+Node *getnode ();
+int addnode ();
+int walklist ();
+void dellist ();
+void delnode ();
+void freenode ();
+void sortlist ();
+#endif /* __STDC__ */
diff --git a/gnu/usr.bin/cvs/lib/mkdir.c b/gnu/usr.bin/cvs/lib/mkdir.c
new file mode 100644
index 0000000..b17cca2
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/mkdir.c
@@ -0,0 +1,125 @@
+/* mkrmdir.c -- BSD compatible directory functions for System V
+ Copyright (C) 1988, 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 <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#ifndef STDC_HEADERS
+extern int errno;
+#endif
+
+/* mkdir and rmdir adapted from GNU tar. */
+
+/* Make directory DPATH, with permission mode DMODE.
+
+ Written by Robert Rother, Mariah Corporation, August 1985
+ (sdcsvax!rmr or rmr@uscd). If you want it, it's yours.
+
+ Severely hacked over by John Gilmore to make a 4.2BSD compatible
+ subroutine. 11Mar86; hoptoad!gnu
+
+ Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
+ subroutine didn't return EEXIST. It does now. */
+
+int
+mkdir (dpath, dmode)
+ char *dpath;
+ int dmode;
+{
+ int cpid, status;
+ struct stat statbuf;
+
+ if (stat (dpath, &statbuf) == 0)
+ {
+ errno = EEXIST; /* stat worked, so it already exists. */
+ return -1;
+ }
+
+ /* If stat fails for a reason other than non-existence, return error. */
+ if (errno != ENOENT)
+ return -1;
+
+ cpid = fork ();
+ switch (cpid)
+ {
+ case -1: /* Cannot fork. */
+ return -1; /* errno is set already. */
+
+ case 0: /* Child process. */
+ /* Cheap hack to set mode of new directory. Since this child
+ process is going away anyway, we zap its umask.
+ This won't suffice to set SUID, SGID, etc. on this
+ directory, so the parent process calls chmod afterward. */
+ status = umask (0); /* Get current umask. */
+ umask (status | (0777 & ~dmode)); /* Set for mkdir. */
+ execl ("/bin/mkdir", "mkdir", dpath, (char *) 0);
+ _exit (1);
+
+ default: /* Parent process. */
+ while (wait (&status) != cpid) /* Wait for kid to finish. */
+ /* Do nothing. */ ;
+
+ if (status & 0xFFFF)
+ {
+ errno = EIO; /* /bin/mkdir failed. */
+ return -1;
+ }
+ return chmod (dpath, dmode);
+ }
+}
+
+/* Remove directory DPATH.
+ Return 0 if successful, -1 if not. */
+
+int
+rmdir (dpath)
+ char *dpath;
+{
+ int cpid, status;
+ struct stat statbuf;
+
+ if (stat (dpath, &statbuf) != 0)
+ return -1; /* stat set errno. */
+
+ if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
+ {
+ errno = ENOTDIR;
+ return -1;
+ }
+
+ cpid = fork ();
+ switch (cpid)
+ {
+ case -1: /* Cannot fork. */
+ return -1; /* errno is set already. */
+
+ case 0: /* Child process. */
+ execl ("/bin/rmdir", "rmdir", dpath, (char *) 0);
+ _exit (1);
+
+ default: /* Parent process. */
+ while (wait (&status) != cpid) /* Wait for kid to finish. */
+ /* Do nothing. */ ;
+
+ if (status & 0xFFFF)
+ {
+ errno = EIO; /* /bin/rmdir failed. */
+ return -1;
+ }
+ return 0;
+ }
+}
diff --git a/gnu/usr.bin/cvs/lib/myndbm.c b/gnu/usr.bin/cvs/lib/myndbm.c
new file mode 100644
index 0000000..8069698
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/myndbm.c
@@ -0,0 +1,212 @@
+/*
+ * 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.3 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 char rcsid[] = "@(#)myndbm.c 1.5 92/03/31";
+#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 = rindex (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..d71acdf
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/myndbm.h
@@ -0,0 +1,44 @@
+/* @(#)myndbm.h 1.3 92/02/29 */
+
+#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
+
+#if __STDC__
+DBM *mydbm_open (char *file, int flags, int mode);
+void mydbm_close (DBM * db);
+datum mydbm_fetch (DBM * db, datum key);
+datum mydbm_firstkey (DBM * db);
+datum mydbm_nextkey (DBM * db);
+#else
+DBM *mydbm_open ();
+void mydbm_close ();
+datum mydbm_fetch ();
+datum mydbm_firstkey ();
+datum mydbm_nextkey ();
+#endif /* __STDC__ */
+
+#endif /* MY_NDBM */
diff --git a/gnu/usr.bin/cvs/lib/regex.c b/gnu/usr.bin/cvs/lib/regex.c
new file mode 100644
index 0000000..3bccfd3
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/regex.c
@@ -0,0 +1,4867 @@
+/* Extended regular expression matching and search library,
+ version 0.4.
+ (Implements POSIX draft P10003.2/D11.2, except for multibyte characters.)
+
+ Copyright (C) 1985, 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. */
+
+#if defined (_AIX) && !defined (REGEX_MALLOC)
+ #pragma alloca
+#endif
+
+#define _GNU_SOURCE
+
+/* For interactive testing, compile with -Dtest. Then this becomes
+ a self-contained program which reads a pattern, describes how it
+ compiles, then reads a string and searches for it. If a command-line
+ argument is present, it is taken to be the value for obscure_syntax (in
+ decimal). The default is 0 (Emacs-style syntax).
+
+ If DEBUG is defined, this prints many voluminous messages about what
+ it is doing (if the variable `debug' is nonzero). */
+
+
+/* The `emacs' switch turns on certain matching commands
+ that make sense only in Emacs. */
+#ifdef emacs
+#include "config.h"
+#include "lisp.h"
+#include "buffer.h"
+#include "syntax.h"
+
+/* Emacs uses `NULL' as a predicate. */
+#undef NULL
+
+#else /* not emacs */
+
+/* POSIX.1 says that <unistd.h> might need <sys/types.h>. We also need
+ it for regex.h. */
+#include <sys/types.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if defined (USG) || defined (POSIX) || defined (STDC_HEADERS)
+#ifndef BSTRING
+#include <string.h>
+#ifndef bcopy
+#define bcopy(s,d,n) memcpy ((d), (s), (n))
+#endif
+#ifndef bcmp
+#define bcmp(s1,s2,n) memcmp ((s1), (s2), (n))
+#endif
+#ifndef bzero
+#define bzero(s,n) memset ((s), 0, (n))
+#endif
+#endif /* not BSTRING */
+#endif /* USG or POSIX or STDC_HEADERS */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else /* not STDC_HEADERS */
+char *malloc ();
+char *realloc ();
+#endif /* not STDC_HEADERS */
+
+/* If debugging, we use standard I/O. */
+#ifdef DEBUG
+#include <stdio.h>
+#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(3) etc. are used for the character classes. */
+#include <ctype.h>
+#ifndef isgraph
+#define isgraph(c) (isprint (c) && !isspace (c))
+#endif
+#ifndef isblank
+#define isblank(c) ((c) == ' ' || (c) == '\t')
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef SIGN_EXTEND_CHAR
+#ifdef __CHAR_UNSIGNED__ /* for, e.g., IBM RT */
+#define SIGN_EXTEND_CHAR(c) (((c)^128) - 128) /* As in Harbison and Steele. */
+#else
+#define SIGN_EXTEND_CHAR /* As nothing. */
+#endif /* not CHAR_UNSIGNED */
+#endif /* not SIGN_EXTEND_CHAR */
+
+/* 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, size) (realloc (source, size))
+
+#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__ */
+#ifdef sparc
+#include <alloca.h>
+#else /* not __GNUC__ or sparc */
+char *alloca ();
+#endif /* not sparc */
+#endif /* not __GNUC__ */
+
+#endif /* not alloca */
+
+/* Still not REGEX_MALLOC. */
+
+#define REGEX_ALLOCATE alloca
+
+/* Requires a `char *destination' declared. */
+#define REGEX_REALLOCATE(source, size) \
+ (destination = (char *) alloca (size), \
+ bcopy (source, destination, size), \
+ destination)
+
+#endif /* not REGEX_MALLOC */
+
+/* (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 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))
+
+/* 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. */
+ no_pop_jump,
+
+ /* Same as no_pop_jump, but marks the end of an alternative. */
+ jump_past_next_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. */
+ 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 no_pop_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,
+
+ /* Used like on_failure_jump except has to succeed n times; The
+ two-byte relative address following it is useless until then.
+ The address is followed by two more bytes containing n. */
+ succeed_n,
+
+ /* Similar to no_pop_jump, but jump n times only; also the
+ relative address following is in turn followed by yet two
+ more bytes containing n. */
+ no_pop_jump_n,
+
+ /* Set the following relative location (two bytes) to the
+ subsequent (two-byte) 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 (*(const char *)((source) + 1)) << 8;\
+ } while (0)
+
+#ifdef DEBUG
+static int
+extract_number (source)
+ unsigned char *source;
+{
+ int answer = *source & 0377;
+ answer += (SIGN_EXTEND_CHAR (*(char *)((source) + 1))) << 8;
+
+ return answer;
+}
+#endif
+
+
+/* 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;
+{
+ *destination = extract_number (*source);
+ *source += 2;
+}
+#endif
+
+
+/* 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)
+
+#ifdef DEBUG
+
+extern void printchar ();
+
+/* Print a compiled pattern buffer in human-readable form, starting at
+ the START pointer into it and ending just before the pointer END. */
+
+static void
+partial_compiled_pattern_printer (pbufp, start, end)
+ struct re_pattern_buffer *pbufp;
+ unsigned char *start;
+ unsigned char *end;
+{
+
+ int mcnt, mcnt2;
+ unsigned char *p = start;
+ unsigned char *pend = end;
+
+ if (start == NULL)
+ {
+ printf ("(null)\n");
+ return;
+ }
+
+ /* This loop loops 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/", *(p - 1) == charset_not ? "_not" : "");
+
+ for (c = 0; p < pend && c < *p * BYTEWIDTH; c++)
+ {
+ if (p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ printchar (c);
+ }
+ 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 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_next_alt:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump_past_next_alt/0/%d", mcnt);
+ break;
+
+ case no_pop_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/no_pop_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 no_pop_jump_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/no_pop_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 wordchar:
+ printf ("/wordchar-emacs");
+ mcnt = (int) Sword;
+ break;
+
+ case syntaxspec:
+ printf ("/syntaxspec");
+ mcnt = *p++;
+ printf ("/%d", mcnt);
+ break;
+
+ case notwordchar:
+ printf ("/notwordchar-emacs");
+ mcnt = (int) Sword;
+ break;
+
+ case notsyntaxspec:
+ printf ("/notsyntaxspec");
+ mcnt = *p++;
+ printf ("/%d", mcnt);
+ break;
+#else /* not emacs */
+ case wordchar:
+ printf ("/wordchar-notemacs");
+ break;
+
+ case notwordchar:
+ printf ("/notwordchar-notemacs");
+ break;
+#endif /* not emacs */
+
+ case begbuf:
+ printf ("/begbuf");
+ break;
+
+ case endbuf:
+ printf ("/endbuf");
+ break;
+
+ default:
+ printf ("?%d", *(p-1));
+ }
+ }
+ printf ("/\n");
+}
+
+static void
+compiled_pattern_printer (pbufp)
+ struct re_pattern_buffer *pbufp;
+{
+ partial_compiled_pattern_printer (pbufp, pbufp->buffer,
+ pbufp->buffer + pbufp->used);
+}
+
+
+static void
+double_string_printer (where, string1, size1, string2, size2)
+ unsigned char *where;
+ unsigned char *string1;
+ unsigned char *string2;
+ int size1;
+ int size2;
+{
+ unsigned this_char;
+
+ if (where == NULL)
+ printf ("(null)");
+ else
+ {
+ if (IS_IN_FIRST_STRING (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]);
+ }
+}
+
+#endif /* DEBUG */
+
+#ifdef DEBUG
+
+/* It is useful to test things that must to 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_COMPILED_PATTERN_PRINTER(p, s, e) \
+ if (debug) partial_compiled_pattern_printer (p, s, e)
+#define DEBUG_DOUBLE_STRING_PRINTER(w, s1, sz1, s2, sz2) \
+ if (debug) double_string_printer (w, s1, sz1, s2, sz2)
+
+#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_COMPILED_PATTERN_PRINTER(p, s, e)
+#define DEBUG_DOUBLE_STRING_PRINTER(w, s1, sz1, s2, sz2)
+
+#endif /* not DEBUG */
+
+typedef char boolean;
+#define false 0
+#define true 1
+
+/* Set by re_set_syntax to the current regexp syntax to recognize. Can
+ also be assigned to more or less arbitrarily. Since we use this as a
+ collection of bits, declaring it unsigned maximizes portability. */
+reg_syntax_t obscure_syntax = 0;
+
+
+/* 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 = obscure_syntax;
+
+ obscure_syntax = 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 */
+ };
+
+/* Other subroutine declarations and macros for regex_compile. */
+
+static void store_jump (), insert_jump (), store_jump_n (),
+ insert_jump_n (), insert_op_2 ();
+
+static boolean at_endline_op_p (), group_in_compile_stack ();
+
+/* 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 PAT_PUSH(c) \
+ do { \
+ GET_BUFFER_SPACE (1); \
+ *b++ = (unsigned char) (c); \
+ } while (0)
+
+
+/* Make sure we have two more bytes of buffer space and then add C1 and
+ C2 to it. */
+#define PAT_PUSH_2(c1, c2) \
+ do { \
+ GET_BUFFER_SPACE (2); \
+ *b++ = (unsigned char) (c1); \
+ *b++ = (unsigned char) (c2); \
+ } while (0)
+
+
+/* Make sure we have two more bytes of buffer space and then add C1, C2
+ and C3 to it. */
+#define PAT_PUSH_3(c1, c2, c3) \
+ do { \
+ GET_BUFFER_SPACE (3); \
+ *b++ = (unsigned char) (c1); \
+ *b++ = (unsigned char) (c2); \
+ *b++ = (unsigned char) (c3); \
+ } while (0)
+
+/* This is not an arbitrary limit: the arguments to the opcodes 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. */
+typedef unsigned char regnum_t;
+#define MAX_REGNUM ((regnum_t) ((1 << BYTEWIDTH) - 1))
+
+
+/* Macros for the compile stack. */
+
+/* This type needs to be able to hold values from 0 to MAX_BUF_SIZE - 1. */
+typedef short 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[(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); \
+ } \
+ } \
+ }
+
+
+/* Read the endpoint of a range from the uncompiled pattern and set the
+ corresponding bits in the compiled pattern. */
+
+#define DO_RANGE \
+ { \
+ char end; \
+ char this_char = p[-2]; \
+ \
+ if (p == pend) \
+ return REG_ERANGE; \
+ PATFETCH (end); \
+ if (syntax & RE_NO_EMPTY_RANGES && this_char > end) \
+ return REG_ERANGE; \
+ while (this_char <= end) \
+ { \
+ SET_LIST_BIT (TRANSLATE (this_char)); \
+ this_char++; \
+ } \
+ }
+
+
+#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 set to zero;
+ `re_nsub' is set to the number of groups in PATTERN;
+ `not_bol' and `not_eol' are set to 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;
+{
+ register unsigned char c, c1;
+ const char *p1;
+
+ /* Points to the end of the buffer, where we should append. */
+ register unsigned char *b;
+
+ /* 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;
+
+ /* Place in the uncompiled pattern (i.e., the {) to
+ which to go back if the interval is invalid. */
+ const char *beg_interval; /* The `{'. */
+ const char *following_left_brace;
+
+ /* Address of beginning of regexp, or inside of last group. */
+ unsigned char *begalt;
+
+ /* 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. The type
+ here is determined by MAX_REGNUM. */
+ regnum_t regnum = 0;
+
+ /* Keeps track of unclosed groups. */
+ compile_stack_type compile_stack;
+
+#ifdef DEBUG
+ DEBUG_PRINT1 ("\nCompiling pattern: ");
+ if (debug)
+ {
+ unsigned debug_count;
+
+ for (debug_count = 0; debug_count < size; debug_count++)
+ printchar (pattern[debug_count]);
+
+ DEBUG_PRINT1 ("\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)
+ { /* EXTEND_BUFFER loses when bufp->allocated is 0. 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)
+ {
+ /* ^ matches the empty string at the beginning of a string (or
+ possibly a line). If RE_CONTEXT_INDEP_ANCHORS is set, ^ is
+ always an operator (and foo^bar is unmatchable). If that bit
+ isn't set, it's an operator only at the beginning of the
+ pattern or after an alternation or open-group operator, or,
+ if RE_NEWLINE_ORDINARY is not set, after a newline (except it
+ can be preceded by other operators that match the empty
+ string); otherwise, it's a normal character. */
+ case '^':
+ {
+ if ( /* If at start of (sub)pattern, it's an operator. */
+ laststart == 0
+ /* If context independent, it's an operator. */
+ || syntax & RE_CONTEXT_INDEP_ANCHORS
+ /* If after a newline, might be an operator. (Since
+ laststart is nonzero here, we know we have at
+ least one byte before the ^.) */
+ || (!(syntax & RE_NEWLINE_ORDINARY) && p[-2] == '\n'))
+ PAT_PUSH (begline);
+ else
+ goto normal_char;
+ }
+ break;
+
+
+ /* $ matches the empty string following the end of the string (or
+ possibly a line). It follows rules dual to those for ^. */
+ 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_op_p (p, pend, syntax))
+ PAT_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);
+
+ /* Get 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 (b, no_pop_jump, laststart);
+ keep_string_p = true;
+ }
+ else
+ /* Anything else. */
+ store_jump (b, maybe_pop_jump, 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, 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 (3);
+ insert_jump (dummy_failure_jump, laststart, laststart + 6, b);
+ b += 3;
+ }
+ }
+ break;
+
+
+ case '.':
+ laststart = b;
+ PAT_PUSH (anychar);
+ break;
+
+
+ case '[':
+ {
+ boolean just_had_a_char_class = false;
+
+ if (p == pend) return REG_EBRACK;
+
+ /* Ensure that we have enough space to push an entire
+ charset: the opcode, the byte count, and the bitmap. */
+ while (b - bufp->buffer + 2 + (1 << BYTEWIDTH) / BYTEWIDTH
+ > bufp->allocated)
+ EXTEND_BUFFER ();
+
+ laststart = b;
+
+ PAT_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. */
+ PAT_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 (just_had_a_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 != ']')
+ {
+ DO_RANGE;
+ }
+
+ else if (p[0] == '-' && p[1] != ']')
+ { /* This handles ranges made up of characters only. */
+ PATFETCH (c1); /* The `-'. */
+ DO_RANGE;
+ }
+
+ /* 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);
+ }
+ just_had_a_char_class = true;
+ }
+ else
+ {
+ c1++;
+ while (c1--)
+ PATUNFETCH;
+ SET_LIST_BIT ('[');
+ SET_LIST_BIT (':');
+ just_had_a_char_class = false;
+ }
+ }
+ else
+ {
+ just_had_a_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_bar;
+ else
+ goto normal_char;
+
+
+ case '|':
+ if (syntax & RE_NO_BK_VBAR)
+ goto handle_bar;
+ 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:
+ if (syntax & RE_NO_EMPTY_GROUPS)
+ {
+ p1 = p;
+ if (!(syntax & RE_NO_BK_PARENS) && *p1 == '\\') p1++;
+
+ /* If found an empty group... */
+ if (*p1 == ')') return REG_BADPAT;
+ }
+
+ 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. */
+ if (regnum <= MAX_REGNUM)
+ {
+ COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
+ PAT_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)
+ store_jump (fixup_alt_jump, jump_past_next_alt, b);
+
+ /* 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;
+ PAT_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_bar:
+ if (syntax & RE_LIMITED_OPS)
+ goto normal_char;
+
+ /* Disallow empty alternatives if RE_NO_EMPTY_ALTS is set.
+ Caveat: can't detect if the vbar is followed by a
+ trailing '$' yet, unless it's the last thing in a
+ pattern; the routine for verifying endlines has to do
+ the rest. */
+ if ((syntax & RE_NO_EMPTY_ALTS)
+ && (!laststart || p == pend
+ || (*p == '$' && p + 1 == pend)
+ || ((syntax & RE_NO_BK_PARENS)
+ ? (p < pend && *p == ')')
+ : (p + 1 < pend && p[0] == '\\' && p[1] == ')'))))
+ return REG_BADPAT;
+
+ /* 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, b);
+ 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 (fixup_alt_jump, jump_past_next_alt, 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 intervals must be allowed. */
+
+ /* For intervals, at least (most) this many matches must
+ be made. */
+ int lower_bound = -1, upper_bound = -1;
+
+ beg_interval = p - 1; /* The `{'. */
+ following_left_brace = NULL;
+
+ 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;
+ }
+
+ if (upper_bound < 0)
+ 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 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 (no_pop_jump, laststart, b + 3, b);
+ b += 3;
+ }
+
+ /* Otherwise, after lower_bound number of succeeds, jump
+ to after the no_pop_jump_n which will be inserted at
+ the end of the buffer, and insert that
+ no_pop_jump_n. */
+ else
+ { /* Set to 5 if only one repetition is allowed and
+ hence no no_pop_jump_n is inserted at the current
+ end of the buffer. Otherwise, need 10 bytes total
+ for the succeed_n and the no_pop_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
+ no_pop_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, no_pop_jump_n, laststart,
+ upper_bound - 1);
+ b += 5;
+
+ /* When hit this when matching, reset the
+ preceding no_pop_jump_n's n to upper_bound - 1. */
+ PAT_PUSH (set_number_at);
+
+ /* Only need to get space for the numbers. */
+ GET_BUFFER_SPACE (4);
+ 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 = NULL;
+
+ if (following_left_brace)
+ goto normal_char;
+ }
+ 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 '=':
+ PAT_PUSH (at_dot);
+ break;
+
+ case 's':
+ laststart = b;
+ PATFETCH (c);
+ PAT_PUSH_2 (syntaxspec, syntax_spec_code[c]);
+ break;
+
+ case 'S':
+ laststart = b;
+ PATFETCH (c);
+ PAT_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
+ break;
+#endif /* emacs */
+
+
+ case 'w':
+ laststart = b;
+ PAT_PUSH (wordchar);
+ break;
+
+
+ case 'W':
+ laststart = b;
+ PAT_PUSH (notwordchar);
+ break;
+
+
+ case '<':
+ PAT_PUSH (wordbeg);
+ break;
+
+ case '>':
+ PAT_PUSH (wordend);
+ break;
+
+ case 'b':
+ PAT_PUSH (wordbound);
+ break;
+
+ case 'B':
+ PAT_PUSH (notwordbound);
+ break;
+
+ case '`':
+ PAT_PUSH (begbuf);
+ break;
+
+ case '\'':
+ PAT_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)
+ {
+ if (syntax & RE_NO_MISSING_BK_REF)
+ return REG_ESUBREG;
+ else
+ goto normal_char;
+ }
+
+ /* Can't back reference to a subexpression if inside of it. */
+ if (group_in_compile_stack (compile_stack, c1))
+ goto normal_char;
+
+ laststart = b;
+ PAT_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;
+
+ PAT_PUSH_2 (exactn, 0);
+ pending_exact = b - 1;
+ }
+
+ PAT_PUSH (c);
+ (*pending_exact)++;
+ break;
+ } /* switch (c) */
+ } /* while p != pend */
+
+
+ /* Through the pattern now. */
+
+ if (fixup_alt_jump)
+ store_jump (fixup_alt_jump, jump_past_next_alt, 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;
+ return REG_NOERROR;
+} /* regex_compile */
+
+/* Subroutines for regex_compile. */
+
+/* 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, op, to)
+ unsigned char *from, *to;
+ re_opcode_t op;
+{
+ from[0] = (unsigned char) op;
+ 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)
+ re_opcode_t op;
+ unsigned char *from, *to, *current_end;
+{
+ register unsigned char *pfrom = current_end; /* Copy from here... */
+ register unsigned 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, op, to, n)
+ unsigned char *from, *to;
+ re_opcode_t op;
+ unsigned n;
+{
+ from[0] = (unsigned char) op;
+ 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)
+ re_opcode_t op;
+ unsigned char *from, *to, *current_end;
+ unsigned n;
+{
+ register unsigned char *pfrom = current_end;
+ register unsigned char *pto = current_end + 5;
+
+ 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)
+ re_opcode_t op;
+ unsigned char *there, *current_end;
+ int num_1, num_2;
+{
+ register unsigned char *pfrom = current_end;
+ register unsigned char *pto = current_end + 5;
+
+ while (pfrom != there)
+ *--pto = *--pfrom;
+
+ there[0] = (unsigned char) op;
+ STORE_NUMBER (there + 1, num_1);
+ STORE_NUMBER (there + 3, num_2);
+}
+
+
+/* Return true if the pattern position P is at a close-group or
+ alternation operator, or if it is a newline and RE_NEWLINE_ORDINARY
+ is not set in SYNTAX. Before checking, though, we skip past all
+ operators that match the empty string.
+
+ This is not quite the dual of what happens with ^. There, we can
+ easily check if the (sub)pattern so far can match only the empty
+ string, because we have seen the pattern, and `laststart' is set to
+ exactly that. But we cannot easily look at the pattern yet to come
+ to see if it matches the empty string; that would require us to compile
+ the pattern, then go back and analyze the pattern after every
+ endline. POSIX required this at one point (that $ be in a
+ ``trailing'' position to be considered an anchor), so we implemented
+ it, but it was slow and took lots of code, and we were never really
+ convinced it worked in all cases. So now it's gone, and we live with
+ the slight inconsistency between ^ and $. */
+
+static boolean
+at_endline_op_p (p, pend, syntax)
+ const char *p, *pend;
+ int syntax;
+{
+ boolean context_indep = !!(syntax & RE_CONTEXT_INDEP_ANCHORS);
+
+ /* Skip past operators that match the empty string. (Except we don't
+ handle empty groups.) */
+ while (p < pend)
+ {
+ if (context_indep && (*p == '^' || *p == '$'))
+ p++;
+
+ /* All others start with \. */
+ else if (*p == '\\' && p + 1 < pend
+ && (p[1] == 'b' || p[1] == 'B'
+ || p[1] == '<' || p[1] == '>'
+ || p[1] == '`' || p[1] == '\''
+#ifdef emacs
+ || p[1] == '='
+#endif
+ ))
+ p += 2;
+
+ else /* Not an empty string operator. */
+ break;
+ }
+
+ /* See what we're at now. */
+ return p < pend
+ && ((!(syntax & RE_NEWLINE_ORDINARY) && *p == '\n')
+ || (syntax & RE_NO_BK_PARENS
+ ? *p == ')'
+ : *p == '\\' && p + 1 < pend && p[1] == ')')
+ || (syntax & RE_NO_BK_VBAR
+ ? *p == '|'
+ : (*p == '\\' && p + 1 < pend && p[1] == '|')));
+}
+
+
+/* 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;
+}
+
+/* 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 *failure_stack_elt_t;
+
+typedef struct
+{
+ failure_stack_elt_t *stack;
+ unsigned size;
+ unsigned avail; /* Offset of next open position. */
+} failure_stack_type;
+
+#define FAILURE_STACK_EMPTY() (failure_stack.avail == 0)
+#define FAILURE_STACK_PTR_EMPTY() (failure_stack_ptr->avail == 0)
+#define FAILURE_STACK_FULL() (failure_stack.avail == failure_stack.size)
+#define FAILURE_STACK_TOP() (failure_stack.stack[failure_stack.avail])
+
+
+/* Initialize FAILURE_STACK. Return 1 if success, 0 if not. */
+
+#define INIT_FAILURE_STACK(failure_stack) \
+ ((failure_stack).stack = (failure_stack_elt_t *) \
+ REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (failure_stack_elt_t)), \
+ (failure_stack).stack == NULL \
+ ? 0 \
+ : ((failure_stack).size = INIT_FAILURE_ALLOC, \
+ (failure_stack).avail = 0, \
+ 1))
+
+
+/* Double the size of FAILURE_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_FAILURE_STACK(failure_stack) \
+ ((failure_stack).size > re_max_failures * MAX_FAILURE_ITEMS \
+ ? 0 \
+ : ((failure_stack).stack = (failure_stack_elt_t *) \
+ REGEX_REALLOCATE ((failure_stack).stack, \
+ ((failure_stack).size << 1) * sizeof (failure_stack_elt_t)), \
+ \
+ (failure_stack).stack == NULL \
+ ? 0 \
+ : ((failure_stack).size <<= 1, \
+ 1)))
+
+
+/* Push PATTERN_OP on FAILURE_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, failure_stack) \
+ ((FAILURE_STACK_FULL () \
+ && !DOUBLE_FAILURE_STACK (failure_stack)) \
+ ? 0 \
+ : ((failure_stack).stack[(failure_stack).avail++] = pattern_op, \
+ 1))
+
+/* This pushes an item onto the failure stack. Must be a four-byte
+ value. Assumes the variable `failure_stack'. Probably should only
+ be called from within `PUSH_FAILURE_POINT'. */
+#define PUSH_FAILURE_ITEM(item) \
+ failure_stack.stack[failure_stack.avail++] = (failure_stack_elt_t) item
+
+/* The complement operation. Assumes stack is nonempty, and pointed to
+ `failure_stack_ptr'. */
+#define POP_FAILURE_ITEM() \
+ failure_stack_ptr->stack[--failure_stack_ptr->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 failure_stack, regstart, regend, reg_info, and
+ num_regs be declared. DOUBLE_FAILURE_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_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \
+ DEBUG_PRINT2 (" Before push, next avail: %d\n", (failure_stack).avail);\
+ DEBUG_PRINT2 (" size: %d\n", (failure_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_FAILURE_STACK (failure_stack)) \
+ return failure_code; \
+ \
+ DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \
+ (failure_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_nothing=%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_COMPILED_PATTERN_PRINTER (bufp, pattern_place, pend); \
+ PUSH_FAILURE_ITEM (pattern_place); \
+ \
+ DEBUG_PRINT2 (" Pushing string 0x%x: `", string_place); \
+ DEBUG_DOUBLE_STRING_PRINTER (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 \
+ ((failure_stack).size - (failure_stack).avail)
+
+/* 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. The other components of BUFP describe the
+ pattern to be used.
+
+ We set the `can_be_null' and `fastmap_accurate' fields in the pattern
+
+ Returns 0 if it can compile a fastmap. Returns -2 if there is an
+ internal error. */
+
+int
+re_compile_fastmap (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ int j, k;
+ failure_stack_type failure_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;
+
+ INIT_FAILURE_STACK (failure_stack);
+
+ bzero (fastmap, 1 << BYTEWIDTH);
+ bufp->fastmap_accurate = 1; /* It will be when we're done. */
+ bufp->can_be_null = 0;
+
+ while (p)
+ {
+ boolean is_a_succeed_n = false;
+
+ if (p == pend)
+ if (FAILURE_STACK_EMPTY ())
+ {
+ bufp->can_be_null = 1;
+ break;
+ }
+ else
+ p = failure_stack.stack[--failure_stack.avail];
+
+#ifdef SWITCH_ENUM_BUG
+ switch ((int) ((re_opcode_t) *p++))
+#else
+ switch ((re_opcode_t) *p++)
+#endif
+ {
+ 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 no_op:
+ case begline:
+ case begbuf:
+ case endbuf:
+ case wordbound:
+ case notwordbound:
+ case wordbeg:
+ case wordend:
+ continue;
+
+
+ case endline:
+ if (!bufp->can_be_null)
+ bufp->can_be_null = 2;
+ break;
+
+
+ case no_pop_jump_n:
+ case pop_failure_jump:
+ case maybe_pop_jump:
+ case no_pop_jump:
+ case jump_past_next_alt:
+ 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 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 (!FAILURE_STACK_EMPTY ()
+ && failure_stack.stack[failure_stack.avail - 1] == p)
+ failure_stack.avail--;
+
+ continue;
+
+
+ case on_failure_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 there can't be any more
+ possibilities for the fastmap beyond pend. */
+ if (p + j < pend)
+ {
+ if (!PUSH_PATTERN_OP (p + j, failure_stack))
+ return -2;
+ }
+
+ if (is_a_succeed_n)
+ EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */
+
+ continue;
+
+
+ case succeed_n:
+ is_a_succeed_n = true;
+
+ /* 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 += 2;
+ continue;
+
+
+ /* I don't understand this case (any of it). --karl */
+ 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)
+ return 0;
+
+ /* 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 before_dot:
+ case at_dot:
+ case after_dot:
+ continue;
+
+
+ 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;
+#endif /* not emacs */
+
+ default:
+ abort ();
+ } /* switch *p++ */
+
+ /* Getting 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, or quit. The test at the top of the
+ loop does these things. */
+ p = pend;
+ } /* while p */
+
+ return 0;
+} /* re_compile_fastmap */
+
+/* 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;
+
+ /* Update the fastmap now if not correct already. */
+ if (fastmap && !bufp->fastmap_accurate)
+ if (re_compile_fastmap (bufp) == -2)
+ return -2;
+
+ /* 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 (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf
+ && range > 0)
+ {
+ if (startpos > 0)
+ return -1;
+ else
+ range = 1;
+ }
+
+ 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 want to skip over 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[*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 (translate
+ ? !fastmap[(unsigned char) translate[(unsigned char) c]]
+ : !fastmap[(unsigned char) 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 == 0)
+ 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 ();
+static void pop_failure_point ();
+
+
+/* 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
+{
+ failure_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_NOTHING_UNSET_VALUE'. */
+#define MATCH_NOTHING_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 something; it sets `matched' flags for the
+ registers corresponding to the group of which we currently are inside.
+ Also records whether this group ever matched something. We only care
+ about this information at `stop_memory', and then only about the
+ previous time through the loop (if the group is starred or whatever).
+ So it is ok to clear all the nonactive registers here. */
+#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 a pointer into one or the other of the strings into an
+ offset from the beginning of that string. */
+#define POINTER_TO_OFFSET(pointer) IS_IN_FIRST_STRING (pointer) \
+ ? (pointer) - string1 \
+ : (pointer) - string2 + size1
+
+/* Registers are set to a sentinel value when they haven't yet matched
+ anything. */
+#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 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)
+
+
+/* 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.
+
+ We assume there is a string1, so use this in conjunction with
+ AT_STRINGS_BEG. */
+#define LETTER_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 || AT_STRINGS_END || LETTER_P (d - 1) != LETTER_P (d))
+
+
+/* Free everything we malloc. */
+#ifdef REGEX_MALLOC
+#define FREE_VARIABLES() \
+ do { \
+ free (failure_stack.stack); \
+ free (regstart); \
+ free (regend); \
+ free (old_regstart); \
+ free (old_regend); \
+ free (reg_info); \
+ free (best_regstart); \
+ free (best_regend); \
+ reg_info = NULL; \
+ failure_stack.stack = NULL; \
+ regstart = regend = old_regstart = old_regend \
+ = best_regstart = best_regend = NULL; \
+ } while (0)
+#else /* not REGEX_MALLOC */
+#define FREE_VARIABLES() /* As nothing, since we use alloca. */
+#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)
+ const 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. (If
+ BUFP->caller_allocated_regs is nonzero, we fill REGS->num_regs
+ registers; if zero, we set REGS->num_regs to max (RE_NREGS,
+ re_nsub+1) and allocate the space with malloc before filling.)
+
+ 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)
+ const 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. */
+ failure_stack_type failure_stack;
+#ifdef DEBUG
+ static unsigned failure_id = 0;
+#endif
+
+ /* We fill all the registers internally, independent of what we
+ return, for use in backreferences. The number here includes
+ 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
+ = (const char **) REGEX_ALLOCATE (num_regs * sizeof (char *));
+ const char **regend
+ = (const char **) REGEX_ALLOCATE (num_regs * sizeof (char *));
+
+ /* 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
+ = (const char **) REGEX_ALLOCATE (num_regs * sizeof (char *));
+ const char **old_regend
+ = (const char **) REGEX_ALLOCATE (num_regs * sizeof (char *));
+
+ /* 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 = (register_info_type *)
+ REGEX_ALLOCATE (num_regs * sizeof (register_info_type));
+
+ /* 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;
+ const char **best_regstart
+ = (const char **) REGEX_ALLOCATE (num_regs * sizeof (char *));
+ const char **best_regend
+ = (const char **) REGEX_ALLOCATE (num_regs * sizeof (char *));
+
+ /* Used when we pop values we don't care about. */
+ const char **reg_dummy
+ = (const char **) REGEX_ALLOCATE (num_regs * sizeof (char *));
+ register_info_type *reg_info_dummy = (register_info_type *)
+ REGEX_ALLOCATE (num_regs * sizeof (register_info_type));
+
+#ifdef DEBUG
+ /* Counts the total number of registers pushed. */
+ unsigned num_regs_pushed = 0;
+#endif
+
+ DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
+
+ if (!INIT_FAILURE_STACK (failure_stack))
+ return -2;
+
+ if (!(regstart && regend && old_regstart && old_regend && reg_info
+ && best_regstart && best_regend))
+ {
+ FREE_VARIABLES ();
+ return -2;
+ }
+
+ /* 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
+ \( or ( and \) or ) has been seen for. Also set all registers to
+ inactive and mark them as not having any inner groups, able to
+ match the empty string, matched anything so far, or ever failed. */
+ for (mcnt = 0; 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_NOTHING_UNSET_VALUE;
+ IS_ACTIVE (reg_info[mcnt]) = 0;
+ MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+ EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+ }
+
+ IS_ACTIVE (reg_info[0]) = 1;
+
+ /* 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_COMPILED_PATTERN_PRINTER (bufp, p, pend);
+ DEBUG_PRINT1 ("The string to match is: `");
+ DEBUG_DOUBLE_STRING_PRINTER (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 not end of string, try backtracking. Otherwise done. */
+ if (d != end_match_2)
+ {
+ DEBUG_PRINT1 ("backtracking.\n");
+
+ if (!FAILURE_STACK_EMPTY ())
+ { /* More failure points to try. */
+
+ boolean 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 < 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. */
+ d = best_regend[0];
+
+ if (d >= string1 && d <= end1)
+ dend = end_match_1;
+
+ for (mcnt = 0; 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)
+ {
+ /* If they haven't allocated it, we'll do it. */
+ if (!bufp->caller_allocated_regs)
+ {
+ 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;
+ }
+
+ /* 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 at the
+ beginning. */
+ 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
+ it than were in the pattern, set the extra elements to
+ -1. If we allocated the registers, this is the case,
+ because we always allocate enough to have at least -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_PRINT2 ("%d 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 anything but 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 ();
+ 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. */
+
+ if (c < (unsigned char) (*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_NOTHING_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;
+
+ /* This loop will always terminate, because register 0 is
+ always active. */
+ assert (IS_ACTIVE (reg_info[0]));
+ while (!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)
+ highest_active_reg = r;
+ else
+ {
+ lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+ }
+ }
+
+ /* 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 no_pop_jump_n:
+ is_a_jump_n = true;
+ case pop_failure_jump:
+ case maybe_pop_jump:
+ case no_pop_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 = ((IS_IN_FIRST_STRING (regstart[regno])
+ == IS_IN_FIRST_STRING (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)
+ {
+ 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)
+ {
+ 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)
+ break;
+ goto fail;
+
+
+ /* Match at the very end of the data. */
+ case endbuf:
+ DEBUG_PRINT1 ("EXECUTING endbuf.\n");
+ if (AT_STRINGS_END)
+ 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
+ go through the hassle of checking 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 only 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 a maybe_pop_jump.
+ We change it either to a pop_failure_jump or a no_pop_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. */
+
+ /* 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)
+ p[-3] = (unsigned char) pop_failure_jump;
+
+ 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 it. */
+ if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
+ p[-3] = (unsigned char) pop_failure_jump;
+ 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;
+ }
+ }
+ }
+ p -= 2; /* Point at relative address again. */
+ if ((re_opcode_t) p[-1] != pop_failure_jump)
+ {
+ p[-1] = (unsigned char) no_pop_jump;
+ goto no_pop;
+ }
+ /* 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 aren't interested.
+ Otherwise, we will restore only one register from the
+ stack, since lowest will equal highest in
+ pop_failure_point (since they'll be the same memory
+ location). */
+ unsigned dummy_low, dummy_high;
+ unsigned char *pdummy = NULL;
+
+ DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
+ pop_failure_point (bufp, pend,
+#ifdef DEBUG
+ string1, size1, string2, size2,
+#endif
+ &failure_stack, &pdummy, &pdummy,
+ &dummy_low, &dummy_high,
+ &reg_dummy, &reg_dummy, &reg_info_dummy);
+ }
+ /* Note fall through. */
+
+
+ /* Jump without taking off any failure points. */
+ case no_pop_jump:
+ no_pop:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */
+ DEBUG_PRINT2 ("EXECUTING no_pop_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_next_alt:
+ DEBUG_PRINT1 ("EXECUTING jump_past_next_alt.\n");
+ goto no_pop;
+
+
+ /* 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 no_pop;
+
+
+ /* 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);
+ DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
+
+ /* Originally, this is how many times we HAVE to succeed. */
+ if (mcnt)
+ {
+ 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;
+ }
+#ifdef DEBUG
+ else
+ {
+ fprintf (stderr, "regex: negative n at succeed_n.\n");
+ abort ();
+ }
+#endif /* DEBUG */
+ break;
+
+ case no_pop_jump_n:
+ EXTRACT_NUMBER (mcnt, p + 2);
+ DEBUG_PRINT2 ("EXECUTING no_pop_jump_n %d.\n", mcnt);
+
+ /* Originally, this is how many times we CAN jump. */
+ if (mcnt)
+ {
+ mcnt--;
+ STORE_NUMBER(p + 2, mcnt);
+ goto no_pop;
+ }
+ /* 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);
+ 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 (LETTER_P (d) && (AT_STRINGS_BEG || !LETTER_P (d - 1)))
+ break;
+ goto fail;
+
+ case wordend:
+ DEBUG_PRINT1 ("EXECUTING wordend.\n");
+ if (!AT_STRINGS_BEG && LETTER_P (d - 1)
+ && (!LETTER_P (d) || AT_STRINGS_END))
+ 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 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 notwordchar.\n");
+ mcnt = (int) Sword;
+ matchnotsyntax: /* We goto here from notsyntaxspec. */
+ 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 (!LETTER_P (d))
+ goto fail;
+ SET_REGS_MATCHED ();
+ break;
+
+ case notwordchar:
+ DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
+ PREFETCH;
+ if (LETTER_P (d))
+ goto fail;
+ SET_REGS_MATCHED ();
+ break;
+#endif /* not emacs */
+
+ default:
+ abort ();
+ }
+ continue; /* Successfully executed one pattern command; keep going. */
+
+
+ /* We goto here if a matching operation fails. */
+ fail:
+ if (!FAILURE_STACK_EMPTY ())
+ { /* A restart point is known. Restore to that state. */
+ DEBUG_PRINT1 ("\nFAIL:\n");
+ pop_failure_point (bufp, pend,
+#ifdef DEBUG
+ string1, size1, string2, size2,
+#endif
+ &failure_stack, &p, &d, &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 no_pop_jump_n:
+ is_a_jump_n = true;
+ case maybe_pop_jump:
+ case pop_failure_jump:
+ case no_pop_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. */
+
+
+/* Pops what PUSH_FAILURE_STACK pushes. */
+
+static void
+pop_failure_point (bufp, pattern_end,
+#ifdef DEBUG
+ string1, size1, string2, size2,
+#endif
+ failure_stack_ptr, pattern_place, string_place,
+ lowest_active_reg, highest_active_reg,
+ regstart, regend, reg_info)
+ const struct re_pattern_buffer *bufp; /* These not modified. */
+ unsigned char *pattern_end;
+#ifdef DEBUG
+ unsigned char *string1, *string2;
+ int size1, size2;
+#endif
+ failure_stack_type *failure_stack_ptr; /* These get modified. */
+ const unsigned char **pattern_place;
+ const unsigned char **string_place;
+ unsigned *lowest_active_reg, *highest_active_reg;
+ const unsigned char ***regstart;
+ const unsigned char ***regend;
+ register_info_type **reg_info;
+{
+#ifdef DEBUG
+ /* Type is really unsigned; it's declared this way just to avoid a
+ compiler warning. */
+ failure_stack_elt_t failure_id;
+#endif
+ int this_reg;
+ const unsigned char *string_temp;
+
+ assert (!FAILURE_STACK_PTR_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", failure_stack_ptr->avail);
+ DEBUG_PRINT2 (" size: %d\n", failure_stack_ptr->size);
+
+ assert (failure_stack_ptr->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)
+ *string_place = string_temp;
+
+ DEBUG_PRINT2 (" Popping string 0x%x: `", *string_place);
+ DEBUG_DOUBLE_STRING_PRINTER (*string_place, string1, size1, string2, size2);
+ DEBUG_PRINT1 ("'\n");
+
+ *pattern_place = POP_FAILURE_ITEM ();
+ DEBUG_PRINT2 (" Popping pattern 0x%x: ", *pattern_place);
+ DEBUG_COMPILED_PATTERN_PRINTER (bufp, *pattern_place, pattern_end);
+
+ /* Restore register info. */
+ *highest_active_reg = (unsigned) POP_FAILURE_ITEM ();
+ DEBUG_PRINT2 (" Popping high active reg: %d\n", *highest_active_reg);
+
+ *lowest_active_reg = (unsigned) POP_FAILURE_ITEM ();
+ DEBUG_PRINT2 (" Popping low active reg: %d\n", *lowest_active_reg);
+
+ for (this_reg = *highest_active_reg; this_reg >= *lowest_active_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] = POP_FAILURE_ITEM ();
+ DEBUG_PRINT2 (" end: 0x%x\n", (*regend)[this_reg]);
+
+ (*regstart)[this_reg] = POP_FAILURE_ITEM ();
+ DEBUG_PRINT2 (" start: 0x%x\n", (*regstart)[this_reg]);
+ }
+} /* pop_failure_point */
+
+
+/* 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 no_pop_jump,
+ whereas the rest start with on_failure_jump and end
+ with a no_pop_jump, e.g., here is the pattern for `a|b|c':
+
+ /on_failure_jump/0/6/exactn/1/a/jump_past_next_alt/0/6
+ /on_failure_jump/0/6/exactn/1/b/jump_past_next_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_next_alt. */
+
+ while ((re_opcode_t) p1[mcnt-3] == jump_past_next_alt)
+ {
+ /* `mcnt' holds how many bytes long the alternative
+ is, including the ending `jump_past_next_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_next_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_next_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_next_alt just before it. `mcnt'
+ contains how many bytes long the alternative is. */
+ 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;
+ 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_NOTHING_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 no_pop_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 RE_NREGS registers will be set
+ (and extraneous ones will be filled with -1). */
+ bufp->caller_allocated_regs = 0;
+
+ /* 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, obscure_syntax, 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 compilation. */
+
+#if !defined (emacs)
+
+static struct re_pattern_buffer re_comp_buf;
+
+const 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";
+ }
+
+ /* Match anchors at newlines. */
+ re_comp_buf.newline_anchor = 1;
+
+ ret = regex_compile (s, strlen (s), obscure_syntax, &re_comp_buf);
+
+ return 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 */
+
+/* Entry points compatible with POSIX regex library. 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;
+
+ /* 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 how many registers to return information
+ about, via `nmatch'. We have to pass that on to the matching
+ routines. */
+ private_preg.caller_allocated_regs = 1;
+
+ 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 : NULL);
+
+ /* 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. */
+
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+ int errcode;
+ const regex_t *preg;
+ char *errbuf;
+ size_t errbuf_size;
+{
+ const char *msg
+ = re_error_msg[errcode] == NULL ? "Success" : re_error_msg[errcode];
+ size_t 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 */
+
+#ifdef test
+
+#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
+ };
+
+
+/* Use this to run interactive tests. */
+
+void
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char pat[500];
+ 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)
+ re_set_syntax (atoi (argv[1]));
+
+ buf.allocated = 40;
+ buf.buffer = (unsigned char *) malloc (buf.allocated);
+ buf.fastmap = fastmap;
+ buf.translate = upcase;
+
+ for (;;)
+ {
+ printf ("Pattern = ");
+ gets (pat);
+
+ if (*pat)
+ {
+ void printchar ();
+ 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');
+ }
+
+ printf ("String = ");
+ gets (pat); /* Now read the string to match against */
+
+ i = re_match (&buf, pat, strlen (pat), 0, 0);
+ printf ("Match value %d.\n\n", i);
+ }
+}
+
+
+#if 0
+/* We have a fancier version now, compiled_pattern_printer. */
+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 /* 0 */
+
+
+void
+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);
+}
+#endif /* test */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/gnu/usr.bin/cvs/lib/regex.h b/gnu/usr.bin/cvs/lib/regex.h
new file mode 100644
index 0000000..211ad09
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/regex.h
@@ -0,0 +1,479 @@
+/* Definitions for data structures and routines for the regular
+ expression library, version REPLACE-WITH-VERSION.
+
+ Copyright (C) 1985, 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. */
+
+#ifndef __REGEXP_LIBRARY_H__
+#define __REGEXP_LIBRARY_H__
+
+/* POSIX says that <sys/types.h> must be included before <regex.h>. */
+
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* 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 (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+ POSIX now says that the behavior of * etc. in leading positions is
+ undefined. We have already implemented a previous draft which
+ made those constructs invalid, so we may as well not change the code
+ back. */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator.
+ Furthermore, alternation cannot be first or last in an re, or
+ immediately follow another alternation or begin-group. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches a newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then period doesn't match a null.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, newline in the pattern is an ordinary character.
+ If not set, newline before ^ or after $ allows the ^ or $ to be an
+ anchor. */
+#define RE_NEWLINE_ORDINARY (RE_NEWLINE_ALT << 1)
+
+/* If this bit is not set, then \{ and \} defines an interval,
+ and { and } are literals.
+ If set, then { and } defines an interval, and \{ and \} are literals. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ORDINARY << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then back references (i.e., \<digit>) are not
+ recognized.
+ If not set, then they are. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then you can't have empty alternatives.
+ If not set, then you can. */
+#define RE_NO_EMPTY_ALTS (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then you can't have empty groups.
+ If not set, then you can. */
+#define RE_NO_EMPTY_GROUPS (RE_NO_EMPTY_ALTS << 1)
+
+/* If this bit is set, then an ending range point has to collate higher
+ than or equal to the starting range point.
+ If not set, then when the ending range point collates higher than the
+ starting range point, we consider such a range to be empty. */
+#define RE_NO_EMPTY_RANGES (RE_NO_EMPTY_GROUPS << 1)
+
+/* If this bit is set, then all back references must refer to a preceding
+ subexpression.
+ If not set, then a back reference to a nonexistent subexpression is
+ treated as literal characters. */
+#define RE_NO_MISSING_BK_REF (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, then Regex considers an unmatched close-group
+ operator to be the ordinary character parenthesis.
+ If not set, then an unmatched close-group operator is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_MISSING_BK_REF << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t obscure_syntax;
+
+
+
+/* Define combinations of the above bits for the standard possibilities.
+ (The [[[ comments delimit what gets put into the Texinfo file.) */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_CONTEXT_INDEP_ANCHORS | RE_CONTEXT_INDEP_OPS | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_SYNTAX_POSIX_AWK)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CONTEXT_INDEP_ANCHORS | RE_CONTEXT_INDEP_OPS \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE \
+ | RE_DOT_NOT_NULL | RE_INTERVALS | RE_LIMITED_OPS \
+ | RE_NEWLINE_ORDINARY | RE_NO_EMPTY_RANGES | RE_NO_MISSING_BK_REF)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NEWLINE_ORDINARY | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS | RE_NO_BK_VBAR \
+ | RE_NO_EMPTY_ALTS | RE_NO_EMPTY_GROUPS | RE_NO_EMPTY_RANGES \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+
+
+
+/* Maximum number of duplicates an interval can allow. */
+#undef RE_DUP_MAX
+#define RE_DUP_MAX ((1 << 15) - 1)
+
+
+/* POSIX `cflags' bits (i.e., information for regcomp). */
+
+/* If this bit is set, then use extended regular expression syntax.
+ If not set, then use basic regular expression syntax. */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+ characters in the string.
+ If not set, then anchors do match at newlines. */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+ If not set, then returns differ between not matching and errors. */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec). */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+ the beginning of the string (presumably because it's not the
+ beginning of a line).
+ If not set, then the beginning-of-line operator does match the
+ beginning of the string. */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line. */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Not implemented. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+
+
+
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `no_sub' can be set. After the pattern has been
+ compiled, the `re_nsub' field is available. All other fields are
+ private to the regex routines. */
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+ /* Space that holds the compiled pattern. It is declared as
+ `unsigned char *' because its elements are
+ sometimes used as array indexes. */
+ unsigned char *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t syntax;
+
+ /* Pointer to a fastmap, if any, otherwise zero. re_search uses
+ the fastmap, if there is one, to skip over impossible
+ starting points for matches. */
+ char *fastmap;
+
+ /* Either a translate table to apply to all characters before
+ comparing them, or zero for no translation. The translation
+ is applied to a pattern when it is compiled and to a string
+ when it is matched. */
+ char *translate;
+
+ /* Number of subexpressions found by the compiler. */
+ size_t re_nsub;
+
+ /* Set to 1 by re_compile_fastmap if this pattern can match the
+ null string; 0 prevents the searcher from matching it with
+ the null string. Set to 2 if it might match the null string
+ either at the end of a search range or just before a
+ character listed in the fastmap. */
+ unsigned can_be_null : 2;
+
+ /* Set to zero when regex_compile compiles a pattern; set to one
+ by re_compile_fastmap when it updates the fastmap, if any. */
+ unsigned fastmap_accurate : 1;
+
+ /* If set, regexec reports only success or failure and does not
+ return anything in pmatch. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the
+ beginning of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+
+ /* If set, re_match_2 assumes a non-null REGS argument is
+ initialized. If not set, REGS is initialized to the max of
+ RE_NREGS and re_nsub + 1 registers. */
+ unsigned caller_allocated_regs : 1;
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+
+/* search.c (search_buffer) in Emacs needs this one opcode value. It is
+ defined both in `regex.c' and here. */
+#define RE_EXACTN_VALUE 1
+
+
+
+
+/* Type for byte offsets within the string. POSIX mandates us defining
+ this. */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
+
+
+/* If `caller_allocated_regs' is zero in the pattern buffer, re_match_2
+ returns information about this many registers. */
+#ifndef RE_NREGS
+#define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers. Aside from the different names than
+ `re_registers', POSIX uses an array of structures, instead of a
+ structure of arrays. */
+typedef struct
+{
+ regoff_t rm_so; /* Byte offset from string's start to substring's start. */
+ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
+} regmatch_t;
+
+
+
+
+/* Declarations for routines. */
+
+#if __STDC__
+
+/* Sets the current syntax to SYNTAX. You can also simply assign to the
+ `obscure_syntax' variable. */
+extern reg_syntax_t re_set_syntax (reg_syntax_t syntax);
+
+/* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `obscure_syntax', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+extern const char *re_compile_pattern (const char *pattern, int length,
+ struct re_pattern_buffer *buffer);
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+extern int re_compile_fastmap (struct re_pattern_buffer *buffer);
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+ compiled into BUFFER. Start searching at position START, for RANGE
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->no_sub are nonzero). */
+extern int re_search (struct re_pattern_buffer *buffer,
+ const char *string, int length,
+ int start, int range,
+ struct re_registers *regs);
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+extern int re_search_2 (struct re_pattern_buffer *buffer,
+ const char *string1, int length1,
+ const char *string2, int length2,
+ int start, int range,
+ struct re_registers *regs,
+ int stop);
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int re_match (const struct re_pattern_buffer *buffer,
+ const char *string, int length,
+ int start, struct re_registers *regs);
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int re_match_2 (const struct re_pattern_buffer *buffer,
+ const char *string1, int length1,
+ const char *string2, int length2,
+ int start,
+ struct re_registers *regs,
+ int stop);
+
+
+#ifndef __386BSD__
+/* 4.2 bsd compatibility. */
+#ifndef bsdi
+extern const char *re_comp (const char *);
+#endif
+extern int re_exec (const char *);
+#endif
+
+/* POSIX compatibility. */
+extern int regcomp (regex_t *preg, const char *pattern, int cflags);
+extern int regexec (const regex_t *preg, const char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags);
+extern size_t regerror (int errcode, const regex_t *preg, char *errbuf,
+ size_t errbuf_size);
+extern void regfree (regex_t *preg);
+
+#else /* not __STDC__ */
+
+/* Support old C compilers. */
+#define const
+
+extern reg_syntax_t re_set_syntax ();
+extern char *re_compile_pattern ();
+extern int re_search (), re_search_2 ();
+extern int re_match (), re_match_2 ();
+
+/* 4.2 BSD compatibility. */
+extern char *re_comp ();
+extern int re_exec ();
+
+/* POSIX compatibility. */
+extern int regcomp ();
+extern int regexec ();
+extern size_t regerror ();
+extern void regfree ();
+
+#endif /* not __STDC__ */
+#endif /* not __REGEXP_LIBRARY_H__ */
+
+
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/gnu/usr.bin/cvs/lib/rename.c b/gnu/usr.bin/cvs/lib/rename.c
new file mode 100644
index 0000000..3e0b481
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/rename.c
@@ -0,0 +1,68 @@
+/* rename.c -- BSD compatible directory function for System V
+ Copyright (C) 1988, 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 <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#ifndef STDC_HEADERS
+extern int errno;
+#endif
+
+/* Rename file FROM to file TO.
+ Return 0 if successful, -1 if not. */
+
+int
+rename (from, to)
+ char *from;
+ char *to;
+{
+ struct stat from_stats;
+ int pid, status;
+
+ if (stat (from, &from_stats) == 0)
+ {
+ if (unlink (to) && errno != ENOENT)
+ return -1;
+ if ((from_stats.st_mode & S_IFMT) == S_IFDIR)
+ {
+ /* Need a setuid root process to link and unlink directories. */
+ pid = fork ();
+ switch (pid)
+ {
+ case -1: /* Error. */
+ error (1, errno, "cannot fork");
+
+ case 0: /* Child. */
+ execl (MVDIR, "mvdir", from, to, (char *) 0);
+ error (255, errno, "cannot run `%s'", MVDIR);
+
+ default: /* Parent. */
+ while (wait (&status) != pid)
+ /* Do nothing. */ ;
+
+ errno = 0; /* mvdir printed the system error message. */
+ return status != 0 ? -1 : 0;
+ }
+ }
+ else
+ {
+ if (link (from, to) == 0 && (unlink (from) == 0 || errno == ENOENT))
+ return 0;
+ }
+ }
+ return -1;
+}
diff --git a/gnu/usr.bin/cvs/lib/sighandle.c b/gnu/usr.bin/cvs/lib/sighandle.c
new file mode 100644
index 0000000..1b73b93
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/sighandle.c
@@ -0,0 +1,412 @@
+/* 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.
+ *
+ * @(#)sighandle.c 1.9 92/03/31
+ *
+ *************************************************************************/
+
+#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 */
+
+#ifdef _MINIX
+#undef POSIX /* Minix 1.6 doesn't support POSIX.1 sigaction yet */
+#endif
+
+#ifndef SIGTYPE
+#define SIGTYPE void
+#endif
+
+/* Define the highest signal number (usually) */
+#ifndef SIGMAX
+#define SIGMAX 32
+#endif
+
+/* Define linked list of signal handlers structure */
+struct SIG_hlist {
+ SIGTYPE (*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
+static struct sigaction *SIG_defaults;
+#else
+#ifdef BSD_SIGNALS
+static struct sigvec *SIG_defaults;
+#else
+static SIGTYPE (**SIG_defaults)();
+#endif
+#endif
+
+/* Critical section housekeeping */
+static int SIG_crSectNest = 0; /* Nesting level */
+#ifdef POSIX
+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
+ sigset_t sigset_test;
+#endif
+
+ if (SIG_defaults && SIG_handlers) /* already allocated */
+ return (0);
+
+#ifdef POSIX
+ (void) sigfillset(&sigset_test);
+ for (i = 1; sigismember(&sigset_test, i) == 1; i++)
+#ifdef BROKEN_SIGISMEMBER
+ if ( i >= NSIG )
+ break
+#endif
+ ;
+ 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 = (SIGTYPE (**)())
+ calloc(i, sizeof(SIGTYPE (**)()));
+#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 SIGTYPE 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;
+SIGTYPE (*fn)();
+{
+ int val;
+ struct SIG_hlist *this;
+#ifdef POSIX
+ 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
+ (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
+ 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)) ==
+ (SIGTYPE (*)()) -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
+ (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;
+SIGTYPE (*fn)();
+{
+ int val;
+ struct SIG_hlist *this;
+ struct SIG_hlist *last;
+#ifdef POSIX
+ 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
+ (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
+ 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]) == (SIGTYPE (*)()) -1)
+ val = -1;
+#endif
+#endif
+ }
+
+ /* Unblock the signal */
+#ifdef POSIX
+ (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
+ 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
+ (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/strdup.c b/gnu/usr.bin/cvs/lib/strdup.c
new file mode 100644
index 0000000..4e5af07
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/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/cvs/lib/strippath.c b/gnu/usr.bin/cvs/lib/strippath.c
new file mode 100644
index 0000000..3d606a8
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/strippath.c
@@ -0,0 +1,74 @@
+/* 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. */
+
+#if defined(STDC_HEADERS) || defined(USG)
+#include <string.h>
+#ifndef index
+#define index strchr
+#endif
+#else
+#include <strings.h>
+#endif
+
+#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 = index(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..0c26ac6
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/stripslash.c
@@ -0,0 +1,35 @@
+/* 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(USG)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/* 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..2b728c2
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/subr.c
@@ -0,0 +1,912 @@
+/*
+ * 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.3 kit.
+ *
+ * Various useful functions for the CVS support code.
+ */
+
+#include "cvs.h"
+
+#ifdef _MINIX
+#undef POSIX /* Minix 1.6 doesn't support POSIX.1 sigaction yet */
+#endif
+
+#ifndef VPRINTF_MISSING
+#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
+
+#ifndef lint
+static char rcsid[] = "@(#)subr.c 1.52 92/03/31";
+#endif
+
+#if __STDC__
+static void run_add_arg (char *s);
+static void run_init_prog (void);
+#else
+static void run_add_arg ();
+static void run_init_prog ();
+#endif /* __STDC__ */
+
+extern char *getlogin ();
+extern char *strtok ();
+
+/*
+ * Copies "from" to "to". mallocs a buffer large enough to hold the entire
+ * file and does one read/one write to do the copy. This is reasonable,
+ * since source files are typically not too large.
+ */
+void
+copy_file (from, to)
+ char *from;
+ char *to;
+{
+ struct stat sb;
+ struct utimbuf t;
+ int fdin, fdout;
+ char *buf;
+
+ if (trace)
+ (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
+ 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)
+ {
+ buf = xmalloc ((int) sb.st_size);
+ if (read (fdin, buf, (int) sb.st_size) != (int) sb.st_size)
+ error (1, errno, "cannot read file %s for copying", from);
+ if (write (fdout, buf, (int) sb.st_size) != (int) sb.st_size
+#ifndef FSYNC_MISSING
+ || fsync (fdout) == -1
+#endif
+ )
+ {
+ error (1, errno, "cannot write file %s for copying", to);
+ }
+ free (buf);
+ }
+ (void) close (fdin);
+ 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 */
+ t.actime = sb.st_atime;
+ t.modtime = sb.st_mtime;
+ (void) utime (to, &t);
+}
+
+/*
+ * Returns non-zero if the argument file is a directory, or is a symbolic
+ * link which points to a directory.
+ */
+int
+isdir (file)
+ 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)
+ 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)
+ char *file;
+{
+ struct stat sb;
+
+ if (stat (file, &sb) < 0)
+ return (0);
+ return (1);
+}
+
+/*
+ * Returns non-zero if the argument file is readable.
+ * XXX - must be careful if "cvs" is ever made setuid!
+ */
+int
+isreadable (file)
+ char *file;
+{
+ return (access (file, R_OK) != -1);
+}
+
+/*
+ * Returns non-zero if the argument file is writable
+ * XXX - muct be careful if "cvs" is ever made setuid!
+ */
+int
+iswritable (file)
+ char *file;
+{
+ return (access (file, W_OK) != -1);
+}
+
+/*
+ * Open a file and die if it fails
+ */
+FILE *
+open_file (name, mode)
+ char *name;
+ char *mode;
+{
+ FILE *fp;
+
+ if ((fp = fopen (name, mode)) == NULL)
+ error (1, errno, "cannot open %s", name);
+ return (fp);
+}
+
+/*
+ * Open a file if allowed and return.
+ */
+FILE *
+Fopen (name, mode)
+ char *name;
+ char *mode;
+{
+ if (trace)
+ (void) fprintf (stderr, "-> fopen(%s,%s)\n", name, mode);
+ if (noexec)
+ return (NULL);
+
+ return (fopen (name, mode));
+}
+
+/*
+ * Make a directory and die if it fails
+ */
+void
+make_directory (name)
+ char *name;
+{
+ struct stat buf;
+
+ if (stat (name, &buf) == 0)
+ {
+ if (S_ISDIR (buf.st_mode))
+ {
+ if (access (name, (R_OK | W_OK | X_OK)) == 0)
+ {
+ error (0, 0, "Directory %s already exists", name);
+ return;
+ }
+ else
+ {
+ error (0, 0,
+ "Directory %s already exists but is protected from you",
+ name);
+ }
+ }
+ else
+ 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)
+ char *name;
+{
+ char *cp;
+
+ if (noexec)
+ return;
+
+ if (mkdir (name, 0777) == 0 || errno == EEXIST)
+ return;
+ if (errno != ENOENT)
+ {
+ error (0, errno, "cannot make path to %s", name);
+ return;
+ }
+ if ((cp = rindex (name, '/')) == NULL)
+ return;
+ *cp = '\0';
+ make_directories (name);
+ *cp++ = '/';
+ if (*cp == '\0')
+ return;
+ (void) mkdir (name, 0777);
+}
+
+/*
+ * malloc some data and die if it fails
+ */
+char *
+xmalloc (bytes)
+ int bytes;
+{
+ char *cp;
+
+ if (bytes <= 0)
+ error (1, 0, "bad malloc size %d", bytes);
+ if ((cp = malloc ((unsigned) bytes)) == NULL)
+ error (1, 0, "malloc failed");
+ 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;
+ int bytes;
+{
+ char *cp;
+
+ if (!ptr)
+ return (xmalloc (bytes));
+
+ if (bytes <= 0)
+ error (1, 0, "bad realloc size %d", bytes);
+ if ((cp = realloc (ptr, (unsigned) bytes)) == NULL)
+ error (1, 0, "realloc failed");
+ return (cp);
+}
+
+/*
+ * Duplicate a string, calling xmalloc to allocate some dynamic space
+ */
+char *
+xstrdup (str)
+ char *str;
+{
+ char *s;
+
+ if (str == NULL)
+ return ((char *) NULL);
+ s = xmalloc (strlen (str) + 1);
+ (void) strcpy (s, str);
+ return (s);
+}
+
+/*
+ * Change the mode of a file, either adding write permissions, or removing
+ * all write permissions. Adding write permissions honors the current umask
+ * setting.
+ */
+void
+xchmod (fname, writable)
+ char *fname;
+ int writable;
+{
+ struct stat sb;
+ int mode, oumask;
+
+ if (stat (fname, &sb) < 0)
+ {
+ if (!noexec)
+ error (0, errno, "cannot stat %s", fname);
+ return;
+ }
+ if (writable)
+ {
+ oumask = umask (0);
+ (void) umask (oumask);
+ mode = sb.st_mode | ((S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask);
+ }
+ else
+ {
+ mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH);
+ }
+
+ if (trace)
+ (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname, mode);
+ 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)
+ char *from;
+ char *to;
+{
+ if (trace)
+ (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
+ 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)
+ char *from, *to;
+{
+ if (trace)
+ (void) fprintf (stderr, "-> link(%s,%s)\n", from, to);
+ if (noexec)
+ return (0);
+
+ return (link (from, to));
+}
+
+/*
+ * unlink a file, if possible.
+ */
+int
+unlink_file (f)
+ char *f;
+{
+ if (trace)
+ (void) fprintf (stderr, "-> unlink(%s)\n", f);
+ if (noexec)
+ return (0);
+
+ return (unlink (f));
+}
+
+/*
+ * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
+ *
+ * mallocs a buffer large enough to hold the entire file and does two reads to
+ * load the buffer and calls bcmp to do the cmp. This is reasonable, since
+ * source files are typically not too large.
+ */
+int
+xcmp (file1, file2)
+ char *file1;
+ char *file2;
+{
+ register char *buf1, *buf2;
+ struct stat sb;
+ off_t size;
+ int ret, fd1, fd2;
+
+ 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, &sb) < 0)
+ error (1, errno, "cannot fstat %s", file1);
+ size = sb.st_size;
+ if (fstat (fd2, &sb) < 0)
+ error (1, errno, "cannot fstat %s", file2);
+ if (size == sb.st_size)
+ {
+ if (size == 0)
+ ret = 0;
+ else
+ {
+ buf1 = xmalloc ((int) size);
+ buf2 = xmalloc ((int) size);
+ if (read (fd1, buf1, (int) size) != (int) size)
+ error (1, errno, "cannot read file %s cor comparing", file1);
+ if (read (fd2, buf2, (int) size) != (int) size)
+ error (1, errno, "cannot read file %s for comparing", file2);
+ ret = bcmp (buf1, buf2, (int) size);
+ free (buf1);
+ free (buf2);
+ }
+ }
+ else
+ ret = 1;
+ (void) close (fd1);
+ (void) close (fd2);
+ return (ret);
+}
+
+/*
+ * 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)
+ char *s;
+{
+ char *cp;
+ int dots = 0;
+
+ for (cp = s; *cp; cp++)
+ {
+ if (*cp == '.')
+ 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;
+ int uid;
+
+ uid = getuid ();
+ if (uid == 0)
+ {
+ /* super-user; try getlogin() to distinguish */
+ if (((name = getenv("LOGNAME")) || (name = getenv("USER")) ||
+ (name = getlogin ())) && *name)
+ return (name);
+ }
+ if ((pw = (struct passwd *) getpwuid (uid)) == NULL)
+ {
+ (void) sprintf (uidname, "uid%d", uid);
+ return (uidname);
+ }
+ return (pw->pw_name);
+}
+
+/*
+ * 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 (VPRINTF_MISSING) && __STDC__
+void
+run_setup (char *fmt,...)
+#else
+void
+run_setup (fmt, va_alist)
+ char *fmt;
+ va_dcl
+
+#endif
+{
+#ifndef VPRINTF_MISSING
+ 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 */
+#ifndef VPRINTF_MISSING
+ 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)
+ char *s;
+{
+ run_add_arg (s);
+}
+
+/* VARARGS */
+#if !defined (VPRINTF_MISSING) && __STDC__
+void
+run_args (char *fmt,...)
+#else
+void
+run_args (fmt, va_alist)
+ char *fmt;
+ va_dcl
+
+#endif
+{
+#ifndef VPRINTF_MISSING
+ va_list args;
+
+#endif
+
+ run_init_prog ();
+
+ /* process the varargs into run_prog */
+#ifndef VPRINTF_MISSING
+ 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)
+ 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 = -1;
+ int rerrno = 0;
+ int pid, w;
+
+#ifdef POSIX
+ sigset_t sigset_mask, sigset_omask;
+ struct sigaction act, iact, qact;
+
+#else
+#ifdef BSD_SIGNALS
+ int mask;
+ struct sigvec vec, ivec, qvec;
+
+#else
+ SIGTYPE (*istat) (), (*qstat) ();
+#endif
+#endif
+
+ if (trace)
+ {
+ (void) fprintf (stderr, "-> system(");
+ 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;
+ }
+ }
+
+ /* The output files, if any, are now created. Do the fork and dups */
+#ifdef VFORK_MISSING
+ pid = fork ();
+#else
+ pid = vfork ();
+#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);
+ _exit (127);
+ }
+ else if (pid == -1)
+ {
+ rerrno = errno;
+ goto out;
+ }
+
+ /* the parent. Ignore some signals for now */
+#ifdef POSIX
+ 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)
+ {
+ bzero ((char *) &vec, 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
+ 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)
+ {
+ status = -1;
+ rerrno = errno;
+ }
+ else if (WIFEXITED (status))
+ status = WEXITSTATUS (status);
+ else if (WIFSIGNALED (status))
+ {
+ if (WTERMSIG (status) == SIGPIPE)
+ error (1, 0, "broken pipe");
+ status = 2;
+ }
+ else
+ status = 1;
+
+ /* restore the signals */
+#ifdef POSIX
+ 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 (status);
+}
+
+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)
+ char *cmd, *mode;
+{
+ if (trace)
+ (void) fprintf (stderr, "-> Popen(%s,%s)\n", cmd, mode);
+ if (noexec)
+ return (NULL);
+ return (popen (cmd, mode));
+}
+
+#ifdef lint
+#ifndef __GNUC__
+/* ARGSUSED */
+time_t
+get_date (date, now)
+ char *date;
+ struct timeb *now;
+{
+ time_t foo = 0;
+
+ return (foo);
+}
+#endif
+#endif
diff --git a/gnu/usr.bin/cvs/lib/system.h b/gnu/usr.bin/cvs/lib/system.h
new file mode 100644
index 0000000..6cfd68f
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/system.h
@@ -0,0 +1,223 @@
+/* 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. */
+
+/* @(#)system.h 1.14 92/04/10 */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef S_ISREG /* Doesn't have POSIX.1 stat stuff. */
+#ifndef mode_t
+#define mode_t unsigned short
+#endif
+#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
+#if defined(MKFIFO_MISSING)
+#define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0))
+#endif
+
+#ifdef POSIX
+#include <unistd.h>
+#include <limits.h>
+#ifndef PATH_MAX
+#define PATH_MAX pathconf ("/", _PC_PATH_MAX)
+#endif
+#else
+off_t lseek ();
+#endif
+
+#ifdef TM_IN_SYS_TIME
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#ifdef TIMEB_H_MISSING
+struct timeb {
+ time_t time; /* Seconds since the epoch */
+ unsigned short millitm; /* Field not used */
+#ifdef timezone
+ short tzone;
+#else
+ short timezone;
+#endif
+ short dstflag; /* Field not used */
+};
+#else
+#include <sys/timeb.h>
+#endif
+
+#if defined(FTIME_MISSING) && !defined(HAVE_TIMEZONE)
+#if !defined(timezone)
+extern char *timezone();
+#endif
+#endif
+
+#ifndef POSIX
+#include <sys/param.h>
+#endif
+
+#ifndef _POSIX_PATH_MAX
+#define _POSIX_PATH_MAX 255
+#endif
+
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX _POSIX_PATH_MAX
+#endif
+#endif
+
+#ifdef POSIX
+#include <utime.h>
+#else
+#ifndef ALTOS
+struct utimbuf
+{
+ long actime;
+ long modtime;
+};
+#endif
+int utime ();
+#endif
+
+#if defined(USG) || defined(STDC_HEADERS)
+#include <string.h>
+#ifndef STDC_HEADERS
+#include <memory.h>
+#endif
+#ifndef index
+#define index strchr
+#endif
+#ifndef rindex
+#define rindex strrchr
+#endif
+#ifndef bcopy
+#define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+#ifndef bzero
+#define bzero(s, n) (void) memset ((s), 0, (n))
+#endif
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp((s1), (s2), (n))
+#endif
+#else
+#include <strings.h>
+#endif
+
+#include <errno.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *getenv ();
+char *malloc ();
+char *realloc ();
+char *calloc ();
+extern int errno;
+#endif
+
+#ifdef __GNUC__
+#ifdef bsdi
+#define alloca __builtin_alloca
+#endif
+#else
+#ifdef sparc
+#include <alloca.h>
+#else
+#ifndef _AIX
+/* AIX alloca decl has to be the first thing in the file, bletch! */
+char *alloca ();
+#endif
+#endif
+#endif
+
+#if defined(USG) || defined(POSIX)
+#include <fcntl.h>
+char *getcwd ();
+#else
+#include <sys/file.h>
+char *getwd ();
+#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
+
+#ifdef DIRENT
+#include <dirent.h>
+#ifdef direct
+#undef direct
+#endif
+#define direct dirent
+#else
+#ifdef SYSNDIR
+#include <sys/ndir.h>
+#else
+#ifdef NDIR
+#include <ndir.h>
+#else /* must be BSD */
+#include <sys/dir.h>
+#endif
+#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
+
+#ifndef SIGTYPE
+#define SIGTYPE void
+#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..49cfb6d
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/wait.h
@@ -0,0 +1,29 @@
+/* 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 POSIX
+#include <sys/types.h> /* For pid_t. */
+#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/y.tab.h b/gnu/usr.bin/cvs/lib/y.tab.h
new file mode 100644
index 0000000..4a541d2
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/y.tab.h
@@ -0,0 +1,18 @@
+#define tAGO 257
+#define tDAY 258
+#define tDAYZONE 259
+#define tID 260
+#define tMERIDIAN 261
+#define tMINUTE_UNIT 262
+#define tMONTH 263
+#define tMONTH_UNIT 264
+#define tSEC_UNIT 265
+#define tSNUMBER 266
+#define tUNUMBER 267
+#define tZONE 268
+#define tDST 269
+typedef union {
+ time_t Number;
+ enum _MERIDIAN Meridian;
+} YYSTYPE;
+extern YYSTYPE yylval;
diff --git a/gnu/usr.bin/cvs/lib/yesno.c b/gnu/usr.bin/cvs/lib/yesno.c
new file mode 100644
index 0000000..a705da7
--- /dev/null
+++ b/gnu/usr.bin/cvs/lib/yesno.c
@@ -0,0 +1,37 @@
+/* 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. */
+
+#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..bec0bd6
--- /dev/null
+++ b/gnu/usr.bin/cvs/mkmodules/Makefile
@@ -0,0 +1,12 @@
+PROG = mkmodules
+SRCS = mkmodules.c
+CFLAGS += -I${.CURDIR}/../cvs -I${.CURDIR}/../lib
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD= -L${.CURDIR}/../lib/obj -lcvs
+.else
+LDADD= -L${.CURDIR}/../lib/ -lcvs
+.endif
+
+.include <bsd.prog.mk>
+.include "../../Makefile.inc"
diff --git a/gnu/usr.bin/cvs/mkmodules/mkmodules.1 b/gnu/usr.bin/cvs/mkmodules/mkmodules.1
new file mode 100644
index 0000000..07ba3f5
--- /dev/null
+++ b/gnu/usr.bin/cvs/mkmodules/mkmodules.1
@@ -0,0 +1,65 @@
+.\"
+.\" @(#)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 checkin (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..59ec13a
--- /dev/null
+++ b/gnu/usr.bin/cvs/mkmodules/mkmodules.c
@@ -0,0 +1,395 @@
+/*
+ * 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.3 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"
+
+#undef PATH_MAX
+#define PATH_MAX 1024 /* max number of bytes in pathname */
+
+#ifndef lint
+static char rcsid[] = "@(#)mkmodules.c 1.39 92/03/31";
+#endif
+
+#ifndef DBLKSIZ
+#define DBLKSIZ 4096 /* since GNU ndbm doesn't define it */
+#endif
+
+char *program_name, *command_name;
+
+char *Rcsbin = RCSBIN_DFLT;
+int noexec = 0; /* Here only to satisfy use in subr.c */
+int trace = 0; /* Here only to satisfy use in subr.c */
+
+#if __STDC__
+static int checkout_file (char *file, char *temp);
+static void make_tempfile (char *temp);
+static void mkmodules_usage (void);
+static void rename_rcsfile (char *temp, char *real);
+
+#ifndef MY_NDBM
+static void rename_dbmfile (char *temp);
+static void write_dbmfile (char *temp);
+#endif /* !MY_NDBM */
+
+#else /* !__STDC__ */
+
+static void make_tempfile ();
+static int checkout_file ();
+static void rename_rcsfile ();
+static void mkmodules_usage ();
+
+#ifndef MY_NDBM
+static void write_dbmfile ();
+static void rename_dbmfile ();
+#endif /* !MY_NDBM */
+
+#endif /* __STDC__ */
+
+int
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *getenv ();
+ char temp[PATH_MAX];
+ char *cp;
+#ifdef MY_NDBM
+ DBM *db;
+#endif
+
+ /*
+ * Just save the last component of the path for error messages
+ */
+ if ((program_name = rindex (argv[0], '/')) == NULL)
+ program_name = argv[0];
+ else
+ program_name++;
+
+ 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);
+
+ /*
+ * Now, check out the "loginfo" file, so that it is always up-to-date in
+ * the CVSROOT directory.
+ */
+ make_tempfile (temp);
+ if (checkout_file (CVSROOTADM_LOGINFO, temp) == 0)
+ rename_rcsfile (temp, CVSROOTADM_LOGINFO);
+ else
+ error (0, 0,
+ "no logging of 'cvs commit' messages is done without a %s file",
+ CVSROOTADM_LOGINFO);
+ (void) unlink_file (temp);
+
+ /*
+ * Now, check out the "rcsinfo" file, so that it is always up-to-date in
+ * the CVSROOT directory.
+ */
+ make_tempfile (temp);
+ if (checkout_file (CVSROOTADM_RCSINFO, temp) == 0)
+ rename_rcsfile (temp, CVSROOTADM_RCSINFO);
+ else
+ error (0, 0,
+ "a %s file can be used to configure 'cvs commit' templates",
+ CVSROOTADM_RCSINFO);
+ (void) unlink_file (temp);
+
+ /*
+ * Now, check out the "editinfo" file, so that it is always up-to-date in
+ * the CVSROOT directory.
+ */
+ make_tempfile (temp);
+ if (checkout_file (CVSROOTADM_EDITINFO, temp) == 0)
+ rename_rcsfile (temp, CVSROOTADM_EDITINFO);
+ else
+ error (0, 0,
+ "a %s file can be used to validate log messages",
+ CVSROOTADM_EDITINFO);
+ (void) unlink_file (temp);
+
+ /*
+ * Now, check out the "commitinfo" file, so that it is always up-to-date
+ * in the CVSROOT directory.
+ */
+ make_tempfile (temp);
+ if (checkout_file (CVSROOTADM_COMMITINFO, temp) == 0)
+ rename_rcsfile (temp, CVSROOTADM_COMMITINFO);
+ else
+ error (0, 0,
+ "a %s file can be used to configure 'cvs commit' checking",
+ CVSROOTADM_COMMITINFO);
+ (void) unlink_file (temp);
+ 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 = rindex (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];
+
+ (void) sprintf (dotdir, "%s.dir", temp);
+ (void) sprintf (dotpag, "%s.pag", temp);
+ (void) unlink_file (dotdir);
+ (void) unlink_file (dotpag);
+ error (1, 0, "DBM creation failed; correct above errors");
+ }
+}
+
+static void
+rename_dbmfile (temp)
+ char *temp;
+{
+ char newdir[50], newpag[50];
+ char dotdir[50], dotpag[50];
+ char bakdir[50], bakpag[50];
+
+ (void) sprintf (dotdir, "%s.dir", CVSROOTADM_MODULES);
+ (void) sprintf (dotpag, "%s.pag", CVSROOTADM_MODULES);
+ (void) sprintf (bakdir, "%s%s.dir", BAKPREFIX, CVSROOTADM_MODULES);
+ (void) sprintf (bakpag, "%s%s.pag", BAKPREFIX, CVSROOTADM_MODULES);
+ (void) sprintf (newdir, "%s.dir", temp);
+ (void) sprintf (newpag, "%s.pag", temp);
+
+ (void) chmod (newdir, 0666);
+ (void) chmod (newpag, 0666);
+
+ /* don't mess with me */
+ SIG_beginCrSect ();
+
+ (void) unlink_file (bakdir); /* rm .#modules.dir .#modules.pag */
+ (void) unlink_file (bakpag);
+ (void) rename (dotdir, bakdir); /* mv modules.dir .#modules.dir */
+ (void) rename (dotpag, bakpag); /* mv modules.pag .#modules.pag */
+ (void) rename (newdir, dotdir); /* mv "temp".dir modules.dir */
+ (void) rename (newpag, dotpag); /* mv "temp".pag modules.pag */
+
+ /* OK -- make my day */
+ SIG_endCrSect ();
+}
+
+#endif /* !MY_NDBM */
+
+static void
+rename_rcsfile (temp, real)
+ char *temp;
+ char *real;
+{
+ char bak[50];
+
+ if (chmod (temp, 0444) < 0) /* chmod 444 "temp" */
+ 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 ()
+{
+}
+
+static void
+mkmodules_usage ()
+{
+ (void) fprintf (stderr, "Usage: %s modules-directory\n", program_name);
+ exit (1);
+}
diff --git a/gnu/usr.bin/cvs/mkmodules/xxx b/gnu/usr.bin/cvs/mkmodules/xxx
new file mode 100644
index 0000000..f0dd87d
--- /dev/null
+++ b/gnu/usr.bin/cvs/mkmodules/xxx
@@ -0,0 +1,5320 @@
+# 1 "/usr/src/gnu/cvs/mkmodules/mkmodules.c"
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/syslimits.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 14 "/usr/src/gnu/cvs/mkmodules/mkmodules.c" 2
+
+# 1 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 1
+
+
+# 1 "/usr/src/gnu/cvs/mkmodules/../lib/system.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/types.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+typedef unsigned short ushort;
+
+typedef char * caddr_t;
+typedef long daddr_t;
+typedef short dev_t;
+typedef u_long ino_t;
+typedef long off_t;
+typedef u_short nlink_t;
+typedef long swblk_t;
+typedef long segsz_t;
+typedef u_short uid_t;
+typedef u_short gid_t;
+typedef short pid_t;
+typedef u_short mode_t;
+typedef u_long fixpt_t;
+
+
+typedef struct _uquad { u_long val[2]; } u_quad;
+typedef struct _quad { long val[2]; } quad;
+typedef long * qaddr_t;
+
+
+
+
+
+
+# 1 "/usr/include/machine/ansi.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 69 "/usr/include/sys/types.h" 2
+
+
+# 1 "/usr/include/machine/types.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef struct _physadr {
+ int r[1];
+} *physadr;
+
+typedef struct label_t {
+ int val[6];
+} label_t;
+
+typedef u_long vm_offset_t;
+typedef u_long vm_size_t;
+
+
+# 71 "/usr/include/sys/types.h" 2
+
+
+
+
+typedef unsigned long clock_t;
+
+
+
+
+typedef unsigned int size_t;
+
+
+
+
+typedef long time_t;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef long fd_mask;
+
+
+
+
+
+
+typedef struct fd_set {
+ fd_mask fds_bits[(((256 )+(( (sizeof(fd_mask) * 8 ) )-1))/( (sizeof(fd_mask) * 8 ) )) ];
+} fd_set;
+
+
+
+
+
+
+# 132 "/usr/include/sys/types.h"
+
+
+
+
+# 20 "/usr/src/gnu/cvs/mkmodules/../lib/system.h" 2
+
+# 1 "/usr/include/sys/stat.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct stat
+{
+ dev_t st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ dev_t st_rdev;
+ off_t st_size;
+ time_t st_atime;
+ long st_spare1;
+ time_t st_mtime;
+ long st_spare2;
+ time_t st_ctime;
+ long st_spare3;
+ long st_blksize;
+ long st_blocks;
+ u_long st_flags;
+ u_long st_gen;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/cdefs.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 76 "/usr/include/sys/cdefs.h"
+
+
+
+# 114 "/usr/include/sys/stat.h" 2
+
+
+
+mode_t umask (mode_t) ;
+int chmod (const char *, mode_t) ;
+int fstat (int, struct stat *) ;
+int mkdir (const char *, mode_t) ;
+int mkfifo (const char *, mode_t) ;
+int stat (const char *, struct stat *) ;
+
+int fchmod (int, mode_t) ;
+int lstat (const char *, struct stat *) ;
+
+
+
+# 21 "/usr/src/gnu/cvs/mkmodules/../lib/system.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+off_t lseek ();
+
+
+
+
+
+# 1 "/usr/include/time.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/machine/ansi.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 57 "/usr/include/machine/ansi.h"
+
+# 39 "/usr/include/time.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+ long tm_gmtoff;
+ char *tm_zone;
+};
+
+# 1 "/usr/include/sys/cdefs.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 78 "/usr/include/sys/cdefs.h"
+
+# 74 "/usr/include/time.h" 2
+
+
+
+char *asctime (const struct tm *) ;
+clock_t clock (void) ;
+char *ctime (const time_t *) ;
+double difftime (time_t, time_t) ;
+struct tm *gmtime (const time_t *) ;
+struct tm *localtime (const time_t *) ;
+time_t mktime (struct tm *) ;
+size_t strftime (char *, size_t, const char *, const struct tm *) ;
+time_t time (time_t *) ;
+
+
+void tzset (void) ;
+
+
+
+char *timezone (int, int) ;
+void tzsetwall (void) ;
+
+
+
+
+# 72 "/usr/src/gnu/cvs/mkmodules/../lib/system.h" 2
+
+
+
+# 86 "/usr/src/gnu/cvs/mkmodules/../lib/system.h"
+
+# 1 "/usr/include/sys/timeb.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct timeb {
+ time_t time;
+ unsigned short millitm;
+ short timezone;
+ short dstflag;
+};
+# 87 "/usr/src/gnu/cvs/mkmodules/../lib/system.h" 2
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/param.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/types.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 135 "/usr/include/sys/types.h"
+
+# 46 "/usr/include/sys/param.h" 2
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/syslimits.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 56 "/usr/include/sys/param.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/signal.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/machine/trap.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 42 "/usr/include/sys/signal.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/cdefs.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 78 "/usr/include/sys/cdefs.h"
+
+# 90 "/usr/include/sys/signal.h" 2
+
+
+
+typedef void (*sig_t) (int) ;
+
+
+typedef void (*__sighandler_t) (int) ;
+typedef unsigned int sigset_t;
+
+
+int sigaddset (sigset_t *, int) ;
+int sigdelset (sigset_t *, int) ;
+int sigemptyset (sigset_t *) ;
+int sigfillset (sigset_t *) ;
+int sigismember (const sigset_t *, int) ;
+
+
+
+
+
+
+
+
+
+
+
+struct sigaction {
+ __sighandler_t sa_handler;
+ sigset_t sa_mask;
+ int sa_flags;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct sigvec {
+ void (*sv_handler)();
+ int sv_mask;
+ int sv_flags;
+};
+
+
+
+
+
+
+
+struct sigaltstack {
+ char *ss_base;
+ int ss_len;
+ int ss_onstack;
+};
+
+
+
+
+struct sigstack {
+ char *ss_sp;
+ int ss_onstack;
+};
+
+
+
+
+
+
+
+
+struct sigcontext {
+ int sc_onstack;
+ int sc_mask;
+ int sc_sp;
+ int sc_fp;
+ int sc_ap;
+ int sc_pc;
+ int sc_ps;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/types.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 135 "/usr/include/sys/types.h"
+
+# 195 "/usr/include/sys/signal.h" 2
+
+
+
+
+__sighandler_t signal (int, __sighandler_t) ;
+int raise (int) ;
+
+int kill (pid_t, int) ;
+int sigaction (int, const struct sigaction *, struct sigaction *) ;
+int sigpending (sigset_t *) ;
+int sigprocmask (int, const sigset_t *, sigset_t *) ;
+int sigsuspend (const sigset_t *) ;
+
+
+int killpg (pid_t, int) ;
+void psignal (unsigned, const char *) ;
+int sigblock (int) ;
+int siginterrupt (int, int) ;
+int sigpause (int) ;
+int sigreturn (struct sigcontext *) ;
+int sigsetmask (int) ;
+int sigstack (const struct sigstack *, struct sigstack *) ;
+int sigvec (int, struct sigvec *, struct sigvec *) ;
+
+
+
+
+
+# 79 "/usr/include/sys/param.h" 2
+
+
+
+# 1 "/usr/include/machine/param.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 82 "/usr/include/sys/param.h" 2
+
+# 1 "/usr/include/machine/endian.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/cdefs.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 78 "/usr/include/sys/cdefs.h"
+
+# 55 "/usr/include/machine/endian.h" 2
+
+
+
+
+
+
+
+
+
+# 77 "/usr/include/machine/endian.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 106 "/usr/include/machine/endian.h"
+
+
+
+
+
+
+
+
+
+
+
+
+# 83 "/usr/include/sys/param.h" 2
+
+# 1 "/usr/include/machine/limits.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 84 "/usr/include/sys/param.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 97 "/usr/src/gnu/cvs/mkmodules/../lib/system.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct utimbuf
+{
+ long actime;
+ long modtime;
+};
+
+int utime ();
+
+
+# 145 "/usr/src/gnu/cvs/mkmodules/../lib/system.h"
+
+# 1 "/usr/include/strings.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/string.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/machine/ansi.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 57 "/usr/include/machine/ansi.h"
+
+# 38 "/usr/include/string.h" 2
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/cdefs.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 78 "/usr/include/sys/cdefs.h"
+
+# 49 "/usr/include/string.h" 2
+
+
+
+void *memchr (const void *, int, size_t) ;
+int memcmp (const void *, const void *, size_t) ;
+void *memcpy (void *, const void *, size_t) ;
+void *memmove (void *, const void *, size_t) ;
+void *memset (void *, int, size_t) ;
+char *strcat (char *, const char *) ;
+char *strchr (const char *, int) ;
+int strcmp (const char *, const char *) ;
+int strcoll (const char *, const char *) ;
+char *strcpy (char *, const char *) ;
+size_t strcspn (const char *, const char *) ;
+char *strerror (int) ;
+size_t strlen (const char *) ;
+char *strncat (char *, const char *, size_t) ;
+int strncmp (const char *, const char *, size_t) ;
+char *strncpy (char *, const char *, size_t) ;
+char *strpbrk (const char *, const char *) ;
+char *strrchr (const char *, int) ;
+size_t strspn (const char *, const char *) ;
+char *strstr (const char *, const char *) ;
+char *strtok (char *, const char *) ;
+size_t strxfrm (char *, const char *, size_t) ;
+
+
+
+int bcmp (const void *, const void *, size_t) ;
+void bcopy (const void *, void *, size_t) ;
+void bzero (void *, size_t) ;
+int ffs (int) ;
+char *index (const char *, int) ;
+void *memccpy (void *, const void *, int, size_t) ;
+char *rindex (const char *, int) ;
+int strcasecmp (const char *, const char *) ;
+char *strdup (const char *) ;
+void strmode (int, char *) ;
+int strncasecmp (const char *, const char *, size_t) ;
+char *strsep (char **, const char *) ;
+void swab (const void *, void *, size_t) ;
+
+
+
+
+# 36 "/usr/include/strings.h" 2
+
+# 146 "/usr/src/gnu/cvs/mkmodules/../lib/system.h" 2
+
+
+
+# 1 "/usr/include/errno.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern int errno;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 149 "/usr/src/gnu/cvs/mkmodules/../lib/system.h" 2
+
+
+
+
+char *getenv ();
+char *malloc ();
+char *realloc ();
+char *calloc ();
+extern int errno;
+
+
+
+
+
+
+# 173 "/usr/src/gnu/cvs/mkmodules/../lib/system.h"
+
+
+
+
+
+
+# 1 "/usr/include/sys/file.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/fcntl.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/types.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 135 "/usr/include/sys/types.h"
+
+# 46 "/usr/include/sys/fcntl.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 99 "/usr/include/sys/fcntl.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct flock {
+ short l_type;
+ short l_whence;
+ off_t l_start;
+ off_t l_len;
+ pid_t l_pid;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/cdefs.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 78 "/usr/include/sys/cdefs.h"
+
+# 169 "/usr/include/sys/fcntl.h" 2
+
+
+
+int open (const char *, int, ...) ;
+int creat (const char *, mode_t) ;
+int fcntl (int, int, ...) ;
+
+int flock (int, int) ;
+
+
+
+
+
+# 36 "/usr/include/sys/file.h" 2
+
+# 1 "/usr/include/sys/unistd.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 37 "/usr/include/sys/file.h" 2
+
+
+# 73 "/usr/include/sys/file.h"
+
+# 179 "/usr/src/gnu/cvs/mkmodules/../lib/system.h" 2
+
+char *getwd ();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/dir.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/dirent.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct dirent {
+ u_long d_fileno;
+ u_short d_reclen;
+ u_short d_namlen;
+
+
+
+
+ char d_name[255 + 1];
+
+};
+
+
+
+
+
+
+
+
+
+
+
+typedef struct _dirdesc {
+ int dd_fd;
+ long dd_loc;
+ long dd_size;
+ char *dd_buf;
+ int dd_len;
+ long dd_seek;
+} DIR;
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/cdefs.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 78 "/usr/include/sys/cdefs.h"
+
+# 88 "/usr/include/dirent.h" 2
+
+
+
+DIR *opendir (const char *) ;
+struct dirent *readdir (DIR *) ;
+void rewinddir (DIR *) ;
+int closedir (DIR *) ;
+
+long telldir (const DIR *) ;
+void seekdir (DIR *, long) ;
+int scandir (const char *, struct dirent ***,
+ int (*)(struct dirent *), int (*)(const void *, const void *)) ;
+int alphasort (const void *, const void *) ;
+int getdirentries (int, char *, int, long *) ;
+
+
+
+
+
+
+# 44 "/usr/include/sys/dir.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 208 "/usr/src/gnu/cvs/mkmodules/../lib/system.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 3 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 2
+
+# 1 "/usr/include/stdio.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/cdefs.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 78 "/usr/include/sys/cdefs.h"
+
+# 42 "/usr/include/stdio.h" 2
+
+
+# 1 "/usr/include/machine/ansi.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 57 "/usr/include/machine/ansi.h"
+
+# 44 "/usr/include/stdio.h" 2
+
+
+
+
+
+
+
+
+
+
+typedef long fpos_t;
+
+
+
+
+
+
+
+
+
+
+struct __sbuf {
+ unsigned char *_base;
+ int _size;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef struct __sFILE {
+ unsigned char *_p;
+ int _r;
+ int _w;
+ short _flags;
+ short _file;
+ struct __sbuf _bf;
+ int _lbfsize;
+
+
+ void *_cookie;
+ int (*_close) (void *) ;
+ int (*_read) (void *, char *, int) ;
+ fpos_t (*_seek) (void *, fpos_t, int) ;
+ int (*_write) (void *, const char *, int) ;
+
+
+ struct __sbuf _ub;
+ unsigned char *_up;
+ int _ur;
+
+
+ unsigned char _ubuf[3];
+ unsigned char _nbuf[1];
+
+
+ struct __sbuf _lb;
+
+
+ int _blksize;
+ int _offset;
+} FILE;
+
+
+extern FILE __sF[];
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void clearerr (FILE *) ;
+int fclose (FILE *) ;
+int feof (FILE *) ;
+int ferror (FILE *) ;
+int fflush (FILE *) ;
+int fgetc (FILE *) ;
+int fgetpos (FILE *, fpos_t *) ;
+char *fgets (char *, size_t, FILE *) ;
+FILE *fopen (const char *, const char *) ;
+int fprintf (FILE *, const char *, ...) ;
+int fputc (int, FILE *) ;
+int fputs (const char *, FILE *) ;
+int fread (void *, size_t, size_t, FILE *) ;
+FILE *freopen (const char *, const char *, FILE *) ;
+int fscanf (FILE *, const char *, ...) ;
+int fseek (FILE *, long, int) ;
+int fsetpos (FILE *, const fpos_t *) ;
+long ftell (const FILE *) ;
+int fwrite (const void *, size_t, size_t, FILE *) ;
+int getc (FILE *) ;
+int getchar (void) ;
+char *gets (char *) ;
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+void perror (const char *) ;
+int printf (const char *, ...) ;
+int putc (int, FILE *) ;
+int putchar (int) ;
+int puts (const char *) ;
+int remove (const char *) ;
+int rename (const char *, const char *) ;
+void rewind (FILE *) ;
+int scanf (const char *, ...) ;
+void setbuf (FILE *, char *) ;
+int setvbuf (FILE *, char *, int, size_t) ;
+int sprintf (char *, const char *, ...) ;
+int sscanf (char *, const char *, ...) ;
+FILE *tmpfile (void) ;
+char *tmpnam (char *) ;
+int ungetc (int, FILE *) ;
+int vfprintf (FILE *, const char *, char * ) ;
+int vprintf (const char *, char * ) ;
+int vsprintf (char *, const char *, char * ) ;
+
+
+
+
+
+
+
+
+
+
+char *ctermid (char *) ;
+FILE *fdopen (int, const char *) ;
+int fileno (FILE *) ;
+
+
+
+
+
+
+
+
+char *fgetline (FILE *, size_t *) ;
+int fpurge (FILE *) ;
+int getw (FILE *) ;
+int pclose (FILE *) ;
+FILE *popen (const char *, const char *) ;
+int putw (int, FILE *) ;
+void setbuffer (FILE *, char *, int) ;
+int setlinebuf (FILE *) ;
+char *tempnam (const char *, const char *) ;
+int snprintf (char *, size_t, const char *, ...) ;
+int vsnprintf (char *, size_t, const char *, char * ) ;
+int vscanf (const char *, char * ) ;
+int vsscanf (const char *, const char *, char * ) ;
+
+
+
+
+
+
+
+
+
+
+
+
+
+FILE *funopen (const void *,
+ int (*)(void *, char *, int),
+ int (*)(void *, const char *, int),
+ fpos_t (*)(void *, fpos_t, int),
+ int (*)(void *)) ;
+
+
+
+
+
+
+
+
+
+int __srget (FILE *) ;
+int __svfscanf (FILE *, const char *, char * ) ;
+int __swbuf (int, FILE *) ;
+
+
+
+
+
+
+
+
+static inline int __sputc(int _c, FILE *_p) {
+ if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n'))
+ return (*_p->_p++ = _c);
+ else
+ return (__swbuf(_c, _p));
+}
+# 331 "/usr/include/stdio.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 4 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 2
+
+# 1 "/usr/include/ctype.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern char _ctype_[];
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 5 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 2
+
+# 1 "/usr/include/pwd.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 1 "/usr/include/sys/types.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 135 "/usr/include/sys/types.h"
+
+# 39 "/usr/include/pwd.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct passwd {
+ char *pw_name;
+ char *pw_passwd;
+ int pw_uid;
+ int pw_gid;
+ time_t pw_change;
+ char *pw_class;
+ char *pw_gecos;
+ char *pw_dir;
+ char *pw_shell;
+ time_t pw_expire;
+};
+
+# 1 "/usr/include/sys/cdefs.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 78 "/usr/include/sys/cdefs.h"
+
+# 72 "/usr/include/pwd.h" 2
+
+
+
+struct passwd *getpwuid (uid_t) ;
+struct passwd *getpwnam (const char *) ;
+
+struct passwd *getpwent (void) ;
+int setpassent (int) ;
+int setpwent (void) ;
+void endpwent (void) ;
+
+
+
+
+# 6 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 2
+
+# 1 "/usr/include/signal.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 222 "/usr/include/signal.h"
+
+# 7 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 2
+
+# 1 "/usr/src/gnu/cvs/mkmodules/../cvs/hash.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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[151 ];
+ struct list *next;
+};
+typedef struct list List;
+
+struct entnode
+{
+ char *version;
+ char *timestamp;
+ char *options;
+ char *tag;
+ char *date;
+};
+typedef struct entnode Entnode;
+
+
+List *getlist (void);
+Node *findnode (List * list, char *key);
+Node *getnode (void);
+int addnode (List * list, Node * p);
+int walklist (List * list, int (*proc) ());
+void dellist (List ** listp);
+void delnode (Node * p);
+void freenode (Node * p);
+void sortlist (List * list, int (*comp) ());
+# 77 "/usr/src/gnu/cvs/mkmodules/../cvs/hash.h"
+
+# 8 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 2
+
+# 1 "/usr/src/gnu/cvs/mkmodules/../cvs/rcs.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct rcsnode
+{
+ int refcount;
+ int flags;
+ char *path;
+ char *head;
+ char *branch;
+ List *symbols;
+ List *versions;
+ List *dates;
+};
+typedef struct rcsnode RCSNode;
+
+struct rcsversnode
+{
+ char *version;
+ char *date;
+ char *next;
+ List *branches;
+};
+typedef struct rcsversnode RCSVers;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+List *RCS_parsefiles (List * files, char *xrepos);
+RCSNode *RCS_parse (char *file, char *repos);
+RCSNode *RCS_parsercsfile (char *rcsfile);
+char *RCS_check_kflag (char *arg);
+char *RCS_getdate (RCSNode * rcs, char *date, int force_tag_match);
+char *RCS_gettag (RCSNode * rcs, char *tag, int force_tag_match);
+char *RCS_getversion (RCSNode * rcs, char *tag, char *date,
+ int force_tag_match);
+char *RCS_magicrev (RCSNode *rcs, char *rev);
+int RCS_isbranch (char *file, char *rev, List *srcfiles);
+char *RCS_whatbranch (char *file, char *tag, List *srcfiles);
+char *RCS_head (RCSNode * rcs);
+int RCS_datecmp (char *date1, char *date2);
+time_t RCS_getrevtime (RCSNode * rcs, char *rev, char *date, int fudge);
+void RCS_check_tag (char *tag);
+void freercsnode (RCSNode ** rnodep);
+# 102 "/usr/src/gnu/cvs/mkmodules/../cvs/rcs.h"
+
+# 9 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 2
+
+# 1 "/usr/src/gnu/cvs/mkmodules/../lib/regex.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef unsigned reg_syntax_t;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern reg_syntax_t obscure_syntax;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef enum
+{
+ REG_NOERROR = 0,
+ REG_NOMATCH,
+
+
+
+ REG_BADPAT,
+ REG_ECOLLATE,
+ REG_ECTYPE,
+ REG_EESCAPE,
+ REG_ESUBREG,
+ REG_EBRACK,
+ REG_EPAREN,
+ REG_EBRACE,
+ REG_BADBR,
+ REG_ERANGE,
+ REG_ESPACE,
+ REG_BADRPT,
+
+
+ REG_EEND,
+ REG_ESIZE,
+ REG_ERPAREN
+} reg_errcode_t;
+
+
+
+
+
+
+
+
+
+
+struct re_pattern_buffer
+{
+
+
+
+
+ unsigned char *buffer;
+
+
+ unsigned long allocated;
+
+
+ unsigned long used;
+
+
+ reg_syntax_t syntax;
+
+
+
+
+ char *fastmap;
+
+
+
+
+
+ char *translate;
+
+
+ size_t re_nsub;
+
+
+
+
+
+
+ unsigned can_be_null : 2;
+
+
+
+ unsigned fastmap_accurate : 1;
+
+
+
+ unsigned no_sub : 1;
+
+
+
+ unsigned not_bol : 1;
+
+
+ unsigned not_eol : 1;
+
+
+ unsigned newline_anchor : 1;
+
+
+
+
+ unsigned caller_allocated_regs : 1;
+
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+
+
+
+
+
+
+
+
+
+
+typedef int regoff_t;
+
+
+
+
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+typedef struct
+{
+ regoff_t rm_so;
+ regoff_t rm_eo;
+} regmatch_t;
+
+
+
+
+
+
+
+
+
+
+extern reg_syntax_t re_set_syntax (reg_syntax_t syntax);
+
+
+
+
+extern const char *re_compile_pattern (const char *pattern, int length,
+ struct re_pattern_buffer *buffer);
+
+
+
+
+
+extern int re_compile_fastmap (struct re_pattern_buffer *buffer);
+
+
+
+
+
+
+
+extern int re_search (struct re_pattern_buffer *buffer,
+ const char *string, int length,
+ int start, int range,
+ struct re_registers *regs);
+
+
+
+
+extern int re_search_2 (struct re_pattern_buffer *buffer,
+ const char *string1, int length1,
+ const char *string2, int length2,
+ int start, int range,
+ struct re_registers *regs,
+ int stop);
+
+
+
+
+extern int re_match (const struct re_pattern_buffer *buffer,
+ const char *string, int length,
+ int start, struct re_registers *regs);
+
+
+
+extern int re_match_2 (const struct re_pattern_buffer *buffer,
+ const char *string1, int length1,
+ const char *string2, int length2,
+ int start,
+ struct re_registers *regs,
+ int stop);
+
+
+
+
+
+
+
+
+
+
+
+extern int regcomp (regex_t *preg, const char *pattern, int cflags);
+extern int regexec (const regex_t *preg, const char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags);
+extern size_t regerror (int errcode, const regex_t *preg, char *errbuf,
+ size_t errbuf_size);
+extern void regfree (regex_t *preg);
+
+# 468 "/usr/src/gnu/cvs/mkmodules/../lib/regex.h"
+
+
+
+
+
+
+
+
+
+
+
+
+# 10 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 2
+
+# 1 "/usr/src/gnu/cvs/mkmodules/../lib/fnmatch.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern int fnmatch (const char *pattern, const char *string, int flags);
+
+
+
+
+
+# 11 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 2
+
+# 1 "/usr/src/gnu/cvs/mkmodules/../lib/getopt.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern char *optarg;
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern int optind;
+
+
+
+
+extern int opterr;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct option
+{
+ char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+
+extern const struct option *_getopt_long_options;
+
+
+
+
+
+
+
+extern int _getopt_long_only;
+
+
+
+
+
+extern int option_index;
+
+
+int gnu_getopt (int argc, char **argv, const char *shortopts);
+int gnu_getopt_long (int argc, char **argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+int gnu_getopt_long_only (int argc, char **argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+
+
+
+
+
+# 12 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 2
+
+# 1 "/usr/src/gnu/cvs/mkmodules/../lib/wait.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 13 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 2
+
+# 1 "/usr/src/gnu/cvs/mkmodules/../cvs/config.h" 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern void exit ();
+
+
+
+extern char *getwd ();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# 14 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 2
+
+
+# 1 "/usr/src/gnu/cvs/mkmodules/../cvs/myndbm.h" 1
+
+
+
+
+
+
+typedef struct
+{
+ List *dbm_list;
+ Node *dbm_next;
+} DBM;
+
+typedef struct
+{
+ char *dptr;
+ int dsize;
+} datum;
+
+
+
+
+
+
+
+
+
+
+
+
+
+DBM *mydbm_open (char *file, int flags, int mode);
+void mydbm_close (DBM * db);
+datum mydbm_fetch (DBM * db, datum key);
+datum mydbm_firstkey (DBM * db);
+datum mydbm_nextkey (DBM * db);
+
+
+
+
+
+
+
+
+
+# 16 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h" 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+enum mtype
+{
+ CHECKOUT, TAG, PATCH
+};
+
+
+
+
+
+
+enum classify_type
+{
+ T_UNKNOWN = 1,
+ T_CONFLICT,
+ T_NEEDS_MERGE,
+ T_MODIFIED,
+ T_CHECKOUT,
+ T_ADDED,
+ T_REMOVED,
+ T_REMOVE_ENTRY,
+ T_UPTODATE,
+ T_TITLE
+};
+typedef enum classify_type Ctype;
+
+
+
+
+
+
+
+
+struct vers_ts
+{
+ char *vn_user;
+
+
+
+
+
+ char *vn_rcs;
+
+ char *ts_user;
+ char *ts_rcs;
+ char *options;
+
+ char *tag;
+ char *date;
+ Entnode *entdata;
+ RCSNode *srcfile;
+};
+typedef struct vers_ts Vers_TS;
+
+
+
+
+
+struct stickydirtag
+{
+ int aflag;
+ char *tag;
+ char *date;
+ char *options;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+enum direnter_type
+{
+ R_PROCESS = 1,
+ R_SKIP_FILES,
+ R_SKIP_DIRS,
+ R_SKIP_ALL
+};
+typedef enum direnter_type Dtype;
+
+extern char *program_name, *command_name;
+extern char *Rcsbin, *Editor, *CVSroot;
+extern char *CurDir;
+extern int really_quiet, quiet;
+extern int use_editor;
+extern int cvswrite;
+
+extern int trace;
+extern int noexec;
+extern int logoff;
+
+
+
+int Reader_Lock (char *xrepository);
+DBM *open_module (void);
+FILE *Fopen (char *name, char *mode);
+FILE *open_file (char *name, char *mode);
+List *Find_Dirs (char *repository, int which);
+List *ParseEntries (int aflag);
+char *Make_Date (char *rawdate);
+char *Name_Repository (char *dir, char *update_dir);
+char *Short_Repository (char *repository);
+char *getcaller (void);
+char *time_stamp (char *file);
+char *xmalloc (int bytes);
+char *xrealloc (char *ptr, int bytes);
+char *xstrdup (char *str);
+int No_Difference (char *file, Vers_TS * vers, List * entries);
+int Parse_Info (char *infofile, char *repository, int (*callproc) (), int all);
+int Reader_Lock (char *xrepository);
+int SIG_register (int sig, void (*fn) ());
+int Writer_Lock (List * list);
+int gethostname (char *name, int namelen);
+int ign_name (char *name);
+int isdir (char *file);
+int isfile (char *file);
+int islink (char *file);
+int isreadable (char *file);
+int iswritable (char *file);
+int link_file (char *from, char *to);
+int numdots (char *s);
+int run_exec (char *stin, char *stout, char *sterr, int flags);
+int unlink_file (char *f);
+int update (int argc, char *argv[]);
+int xcmp (char *file1, char *file2);
+int yesno (void);
+time_t get_date (char *date, struct timeb *now);
+void Create_Admin (char *dir, char *repository, char *tag, char *date);
+void Lock_Cleanup (void);
+void ParseTag (char **tagp, char **datep);
+void Scratch_Entry (List * list, char *fname);
+void WriteTag (char *dir, char *tag, char *date);
+void cat_module (int status);
+void check_entries (char *dir);
+void close_module (DBM * db);
+void copy_file (char *from, char *to);
+void error (int status, int errnum, char *message,...);
+void fperror (FILE * fp, int status, int errnum, char *message,...);
+void free_names (int *pargc, char *argv[]);
+void freevers_ts (Vers_TS ** versp);
+void ign_add (char *ign, int hold);
+void ign_add_file (char *file, int hold);
+void ign_setup (void);
+void line2argv (int *pargc, char *argv[], char *line);
+void make_directories (char *name);
+void make_directory (char *name);
+void rename_file (char *from, char *to);
+void run_arg (char *s);
+void run_args (char *fmt,...);
+void run_print (FILE * fp);
+void run_setup (char *fmt,...);
+void strip_path (char *path);
+void update_delproc (Node * p);
+void usage (char **cpp);
+void xchmod (char *fname, int writable);
+int Checkin (int type, char *file, char *repository, char *rcs, char *rev,
+ char *tag, char *message, List * entries);
+Ctype Classify_File (char *file, char *tag, char *date, char *options,
+ int force_tag_match, int aflag, char *repository,
+ List *entries, List *srcfiles, Vers_TS **versp);
+List *Find_Names (char *repository, int which, int aflag,
+ List ** optentries);
+void Register (List * list, char *fname, char *vn, char *ts,
+ char *options, char *tag, char *date);
+void Update_Logfile (char *repository, char *xmessage, char *xrevision,
+ FILE * xlogfp, List * xchanges);
+Vers_TS *Version_TS (char *repository, char *options, char *tag,
+ char *date, char *user, int force_tag_match,
+ int set_time, List * entries, List * xfiles);
+void do_editor (char *dir, char *message, char *repository,
+ List * changes);
+int do_module (DBM * db, char *mname, enum mtype m_type, char *msg,
+ int (*callback_proc) (), char *where, int shorten,
+ int local_specified, int run_module_prog, char *extra_arg);
+int do_recursion (int (*xfileproc) (), int (*xfilesdoneproc) (),
+ Dtype (*xdirentproc) (), int (*xdirleaveproc) (),
+ Dtype xflags, int xwhich, int xaflag, int xreadlock,
+ int xdosrcs);
+int do_update (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 (int type, char *update_dir, char *revs, char *name,
+ char *repository);
+int start_recursion (int (*fileproc) (), int (*filesdoneproc) (),
+ Dtype (*direntproc) (), int (*dirleaveproc) (),
+ int argc, char *argv[], int local, int which,
+ int aflag, int readlock, char *update_preload,
+ int dosrcs);
+void SIG_beginCrSect ();
+void SIG_endCrSect ();
+# 438 "/usr/src/gnu/cvs/mkmodules/../cvs/cvs.h"
+
+# 15 "/usr/src/gnu/cvs/mkmodules/mkmodules.c" 2
+
+
+
+
+
+
+PATH_MAX +2
+
+
+static char rcsid[] = "@(#)mkmodules.c 1.39 92/03/31";
+
+
+
+
+
+
+char *program_name, *command_name;
+
+char *Rcsbin = "" ;
+int noexec = 0;
+int trace = 0;
+
+
+static int checkout_file (char *file, char *temp);
+static void make_tempfile (char *temp);
+static void mkmodules_usage (void);
+static void rename_rcsfile (char *temp, char *real);
+
+
+
+
+
+
+# 60 "/usr/src/gnu/cvs/mkmodules/mkmodules.c"
+
+
+int
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *getenv ();
+ char temp[PATH_MAX +2 ];
+ char *cp;
+
+ DBM *db;
+
+
+
+
+
+ if ((program_name = rindex (argv[0], '/')) == 0 )
+ program_name = argv[0];
+ else
+ program_name++;
+
+ if (argc != 2)
+ mkmodules_usage ();
+
+ if ((cp = getenv ("RCSBIN" )) != 0 )
+ Rcsbin = cp;
+
+
+
+
+
+ if (Rcsbin[0] != '\0')
+ {
+ int len = strlen (Rcsbin);
+ char *rcsbin;
+
+ if (Rcsbin[len - 1] != '/')
+ {
+ rcsbin = Rcsbin;
+ Rcsbin = xmalloc (len + 2);
+ (void) strcpy (Rcsbin, rcsbin);
+ (void) strcat (Rcsbin, "/");
+ }
+ }
+
+ if (chdir (argv[1]) < 0)
+ error (1, errno, "cannot chdir to %s", argv[1]);
+
+
+
+
+ make_tempfile (temp);
+ switch (checkout_file ("modules" , temp))
+ {
+
+ case 0:
+
+
+ if ((db = mydbm_open (temp, 0x0000 , 0666)) != 0 )
+ mydbm_close (db);
+
+
+
+
+ rename_rcsfile (temp, "modules" );
+ break;
+
+ case -1:
+ (void) unlink_file (temp);
+ exit (1);
+
+
+ default:
+ error (0, 0,
+ "'cvs checkout' is less functional without a %s file",
+ "modules" );
+ break;
+ }
+
+ (void) unlink_file (temp);
+
+
+
+
+
+ make_tempfile (temp);
+ if (checkout_file ("loginfo" , temp) == 0)
+ rename_rcsfile (temp, "loginfo" );
+ else
+ error (0, 0,
+ "no logging of 'cvs commit' messages is done without a %s file",
+ "loginfo" );
+ (void) unlink_file (temp);
+
+
+
+
+
+ make_tempfile (temp);
+ if (checkout_file ("rcsinfo" , temp) == 0)
+ rename_rcsfile (temp, "rcsinfo" );
+ else
+ error (0, 0,
+ "a %s file can be used to configure 'cvs commit' templates",
+ "rcsinfo" );
+ (void) unlink_file (temp);
+
+
+
+
+
+ make_tempfile (temp);
+ if (checkout_file ("editinfo" , temp) == 0)
+ rename_rcsfile (temp, "editinfo" );
+ else
+ error (0, 0,
+ "a %s file can be used to validate log messages",
+ "editinfo" );
+ (void) unlink_file (temp);
+
+
+
+
+
+ make_tempfile (temp);
+ if (checkout_file ("commitinfo" , temp) == 0)
+ rename_rcsfile (temp, "commitinfo" );
+ else
+ error (0, 0,
+ "a %s file can be used to configure 'cvs commit' checking",
+ "commitinfo" );
+ (void) unlink_file (temp);
+ return (0);
+}
+
+
+
+
+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", ".#" , seed++);
+ if ((fd = open (temp, 0x0200 | 0x0800 | 0x0002 , 0666)) != -1)
+ break;
+ if (errno != 17 )
+ 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 +2 ];
+ int retcode = 0;
+
+ (void) sprintf (rcs, "%s%s", file, ",v" );
+ if (!isfile (rcs))
+ return (1);
+ run_setup ("%s%s -q -p", Rcsbin, "co" );
+ run_arg (rcs);
+ if ((retcode = run_exec ( (char *)0 , temp, (char *)0 , 0x0000 )) != 0)
+ {
+ error (0, retcode == -1 ? errno : 0, "failed to check out %s file", file);
+ }
+ return (retcode);
+}
+
+# 369 "/usr/src/gnu/cvs/mkmodules/mkmodules.c"
+
+
+static void
+rename_rcsfile (temp, real)
+ char *temp;
+ char *real;
+{
+ char bak[50];
+
+ if (chmod (temp, 0444) < 0)
+ error (0, errno, "warning: cannot chmod %s", temp);
+ (void) sprintf (bak, "%s%s", ".#" , real);
+ (void) unlink_file (bak);
+ (void) rename (real, bak);
+ (void) rename (temp, real);
+}
+
+
+
+
+void
+Lock_Cleanup ()
+{
+}
+
+static void
+mkmodules_usage ()
+{
+ (void) fprintf ((&__sF[2]) , "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..937c7d9
--- /dev/null
+++ b/gnu/usr.bin/dc/Makefile
@@ -0,0 +1,7 @@
+PROG= dc
+SRCS= dc.c decimal.c
+CFLAGS+=-I${.CURDIR} -DHAVE_BCOPY=1 -DHAVE_BZERO=1
+DPADD= ${LIBM}
+LDADD= -lm
+
+.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..933b24b
--- /dev/null
+++ b/gnu/usr.bin/dc/dc.c
@@ -0,0 +1,909 @@
+/*
+ * `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;
+ extern char *sys_errlist[];
+ 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/dc.info b/gnu/usr.bin/dc/dc.info
new file mode 100644
index 0000000..a30fea9
--- /dev/null
+++ b/gnu/usr.bin/dc/dc.info
@@ -0,0 +1,330 @@
+This is Info file dc.info, produced by Makeinfo-1.52 from the input
+file dc.texinfo.
+
+ 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.
+
+ 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.
+
+
+File: dc.info, Node: Top, Next: Introduction, Prev: (dir), Up: (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
+
+
+File: dc.info, Node: Introduction, Next: Printing Commands, Prev: Top, Up: Top
+
+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 `q'. `C-c' does not exit; it is used to abort macros
+that are looping, etc. (Currently this is not true; `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 `_'. `-' 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.
+
+
+File: dc.info, Node: Printing Commands, Next: Arithmetic, Prev: Introduction, Up: Top
+
+Printing Commands
+*****************
+
+`p'
+ Prints the value on the top of the stack, without altering the
+ stack. A newline is printed after the value.
+
+`P'
+ Prints the value on the top of the stack, popping it off, and does
+ not print a newline after.
+
+`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.
+
+
+File: dc.info, Node: Arithmetic, Next: Stack Control, Prev: Printing Commands, Up: Top
+
+Arithmetic
+**********
+
+`+'
+ 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.
+
+`-'
+ Pops two values, subtracts the first one popped from the second
+ one popped, and pushes the result.
+
+`*'
+ 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.
+
+`/'
+ 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.
+
+`%'
+ Pops two values, computes the remainder of the division that the
+ `/' 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.
+
+`^'
+ 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.
+
+`v'
+ Pops one value, computes its square root, and pushes that. The
+ precision flag specifies the number of fraction digits in the
+ result.
+
+ Most arithmetic operations are affected by the "precision flag",
+which you can set with the `k' command. The default precision value is
+zero, which means that all arithmetic except for addition and
+subtraction produces integer results.
+
+ The remainder operation (`%') requires some explanation: applied to
+arguments `a' and `b' it produces `a - (b * (a / b))', where `a / b' is
+computed in the current precision.
+
+
+File: dc.info, Node: Stack Control, Next: Registers, Prev: Arithmetic, Up: Top
+
+Stack Control
+*************
+
+`c'
+ Clears the stack, rendering it empty.
+
+`d'
+ Duplicates the value on the top of the stack, pushing another copy
+ of it. Thus, `4d*p' computes 4 squared and prints it.
+
+
+File: dc.info, Node: Registers, Next: Parameters, Prev: Stack Control, Up: Top
+
+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.
+
+`sR'
+ Pop the value off the top of the stack and store it into register
+ R.
+
+`lR'
+ Copy the value in register R, and push it onto the stack. This
+ does not alter the contents of R.
+
+ Each register also contains its own stack. The current register
+ value is the top of the register's stack.
+
+`SR'
+ Pop the value off the top of the (main) stack and push it onto the
+ stack of register R. The previous value of the register becomes
+ inaccessible.
+
+`LR'
+ Pop the value off the top of register R's stack and push it onto
+ the main stack. The previous value in register R's stack, if any,
+ is now accessible via the `lR' command.
+
+ The `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.
+
+
+File: dc.info, Node: Parameters, Next: Strings, Prev: Registers, Up: Top
+
+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; *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.
+
+`i'
+ Pops the value off the top of the stack and uses it to set the
+ input radix.
+
+`o'
+`k'
+ Similarly set the output radix and the precision.
+
+`I'
+ Pushes the current input radix on the stack.
+
+`O'
+`K'
+ Similarly push the current output radix and the current precision.
+
+
+File: dc.info, Node: Strings, Next: Status Inquiry, Prev: Parameters, Up: Top
+
+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 `p' command can accept either and prints the object
+according to its type.
+
+`[CHARACTERS]'
+ Makes a string containing CHARACTERS and pushes it on the stack.
+ For example, `[foo]P' prints the characters `foo' (with no
+ newline).
+
+`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, `[1p]x' executes the macro `1p',
+ which pushes 1 on the stack and prints `1' on a separate line.
+
+ Macros are most often stored in registers; `[1p]sa' stores a macro
+ to print `1' into register `a', and `lax' invokes the macro.
+
+`>R'
+ Pops two values off the stack and compares them assuming they are
+ numbers, executing the contents of register R as a macro if the
+ original top-of-stack is greater. Thus, `1 2>a' will invoke
+ register `a''s contents and `2 1>a' will not.
+
+`<R'
+ Similar but invokes the macro if the original top-of-stack is less.
+
+`=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.
+
+`?'
+ Reads a line from the terminal and executes it. This command
+ allows a macro to request input from the user.
+
+`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).
+
+`Q'
+ Pops a value off the stack and uses it as a count of levels of
+ macro execution to be exited. Thus, `3Q' exits three levels.
+
+
+File: dc.info, Node: Status Inquiry, Next: Notes, Prev: Strings, Up: Top
+
+Status Inquiry
+**************
+
+`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.
+
+`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.
+
+`z'
+ Pushes the current stack depth; the number of objects on the stack
+ before the execution of the `z' command.
+
+`I'
+ Pushes the current value of the input radix.
+
+`O'
+ Pushes the current value of the output radix.
+
+`K'
+ Pushes the current value of the precision.
+
+
+File: dc.info, Node: Notes, Prev: Status Inquiry, Up: Top
+
+Notes
+*****
+
+ The `:' and `;' commands of the Unix DC program are not supported,
+as the documentation does not say what they do. The `!' command is not
+supported, but will be supported as soon as a library for executing a
+line as a command exists.
+
+
+
+Tag Table:
+Node: Top960
+Node: Introduction1440
+Node: Printing Commands2603
+Node: Arithmetic3211
+Node: Stack Control5168
+Node: Registers5468
+Node: Parameters6586
+Node: Strings7659
+Node: Status Inquiry9857
+Node: Notes10571
+
+End Tag Table
diff --git a/gnu/usr.bin/dc/dc.texinfo b/gnu/usr.bin/dc/dc.texinfo
new file mode 100644
index 0000000..15b285f
--- /dev/null
+++ b/gnu/usr.bin/dc/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/dc/decimal.c b/gnu/usr.bin/dc/decimal.c
new file mode 100644
index 0000000..1fb95c1
--- /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_round_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..2b41158
--- /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 make_decimal (), decimal_copy (), decimal_parse ();
+decimal decimal_sqrt (), decimal_expt ();
+
+void decimal_print ();
+
+/* End of decimal.h */
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..fe3a5e9
--- /dev/null
+++ b/gnu/usr.bin/diff/Makefile
@@ -0,0 +1,8 @@
+
+PROG= diff
+SRCS= diff.c analyze.c io.c context.c ed.c normal.c ifdef.c util.c dir.c \
+ version.c regex.c getopt.c getopt1.c side.c cmpbuf.c
+CFLAGS+=-DHAVE_CONFIG_H
+MAN= diff.1
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/diff/analyze.c b/gnu/usr.bin/diff/analyze.c
new file mode 100644
index 0000000..556d388
--- /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..ed8e8ef
--- /dev/null
+++ b/gnu/usr.bin/diff/config.h
@@ -0,0 +1,112 @@
+/* config.h. Generated automatically by configure. */
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if using alloca.c. */
+/* #undef C_ALLOCA */
+
+/* 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 dirent.h. */
+#define DIRENT 1
+
+/* Define if you have alloca.h and it should be used (not 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 if you don't have dirent.h, but have ndir.h. */
+/* #undef NDIR */
+
+/* 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 you don't have dirent.h, but have sys/dir.h. */
+/* #undef SYSDIR */
+
+/* Define if you don't have dirent.h, but have sys/ndir.h. */
+/* #undef SYSNDIR */
+
+/* Define vfork as fork if vfork does not work. */
+/* #undef vfork */
+
+/* Define if the closedir function returns void instead of int. */
+/* #undef VOID_CLOSEDIR */
+
+/* Define if you have dup2. */
+#define HAVE_DUP2 1
+
+/* Define if you have memchr. */
+#define HAVE_MEMCHR 1
+
+/* Define if you have sigaction. */
+#define HAVE_SIGACTION 1
+
+/* Define if you have strerror. */
+#define HAVE_STRERROR 1
+
+/* Define if you have waitpid. */
+#define HAVE_WAITPID 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 <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/wait.h> header file. */
+#define HAVE_SYS_WAIT_H 1
+
+/* 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..5b4b73f
--- /dev/null
+++ b/gnu/usr.bin/diff/context.c
@@ -0,0 +1,464 @@
+/* Context-format output routines 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 "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
+ /* See Posix.2 section 4.17.6.1.4 for this format. */
+ fprintf (outfile, "%s %s\t%s",
+ mark, inf->name, ctime (&inf->stat.st_mtime));
+}
+
+/* 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..6004f84
--- /dev/null
+++ b/gnu/usr.bin/diff/diff.c
@@ -0,0 +1,997 @@
+/* GNU DIFF main routine.
+ 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. */
+
+/* GNU DIFF was written by Mike Haertel, David Hayes,
+ Richard Stallman, Len Tower, and Paul Eggert. */
+
+#define GDIFF_MAIN
+#include "diff.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 usage PARAMS((char const *));
+
+/* 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;
+
+/* 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'},
+ {"binary", 0, 0, 'q'}, /* An alias, no longer recommended */
+ {"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},
+ {0, 0, 0, 0}
+};
+
+int
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int val;
+ int c;
+ int prev = -1;
+ int width = DEFAULT_WIDTH;
+
+ /* Do our initializations. */
+ program = argv[0];
+ output_style = OUTPUT_NORMAL;
+ context = -1;
+ line_end_char = '\n';
+
+ /* 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;
+ length_varies = 1;
+ ignore_some_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;
+ 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;
+ 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. */
+ specify_style (OUTPUT_CONTEXT);
+ 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 ("GNU diff 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;
+ length_varies = 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 (0);
+
+ default:
+ usage ("");
+ }
+ prev = c;
+ }
+
+ if (optind != argc - 2)
+ usage (optind < argc - 2 ? "extra operand" : "missing 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 (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)
+ {
+ 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 ();
+
+ if (ferror (stdout) || fclose (stdout) != 0)
+ fatal ("write error");
+ 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
+usage (reason)
+ char const *reason;
+{
+ if (reason && *reason)
+ fprintf (stderr, "%s: %s\n", program, reason);
+ fflush (stderr);
+ printf ("Usage: %s [options] from-file to-file\n", program);
+ printf ("Options:\n\
+ [-abBcdefhHilnNpPqrstTuvwy] [-C lines] [-D name] [-F regexp]\n\
+ [-I regexp] [-L from-label [-L to-label]] [-S starting-file] [-U lines]\n\
+ [-W columns] [-x pattern] [-X pattern-file]\n");
+ printf ("\
+ [--brief] [--changed-group-format=format] [--context[=lines]] [--ed]\n\
+ [--exclude=pattern] [--exclude-from=pattern-file] [--expand-tabs]\n\
+ [--forward-ed] [--help] [--horizon-lines=lines] [--ifdef=name]\n\
+ [--ignore-all-space] [--ignore-blank-lines] [--ignore-case]\n");
+ printf ("\
+ [--ignore-matching-lines=regexp] [--ignore-space-change]\n\
+ [--initial-tab] [--label=from-label [--label=to-label]]\n\
+ [--left-column] [--minimal] [--new-file] [--new-group-format=format]\n\
+ [--new-line-format=format] [--old-group-format=format]\n");
+ printf ("\
+ [--old-line-format=format] [--paginate] [--rcs] [--recursive]\n\
+ [--report-identical-files] [--sdiff-merge-assist] [--show-c-function]\n\
+ [--show-function-line=regexp] [--side-by-side] [--speed-large-files]\n\
+ [--starting-file=starting-file] [--suppress-common-lines] [--text]\n");
+ printf ("\
+ [--unchanged-group-format=format] [--unchanged-line-format=format]\n\
+ [--unidirectional-new-file] [--unified[=lines]] [--version]\n\
+ [--width=columns]\n");
+ exit (reason ? 2 : 0);
+}
+
+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 popular file types */
+ /* S_ISLNK is impossible with `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 && strcmp (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 = strrchr (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].stat.st_ino == inf[1].stat.st_ino
+ && inf[0].stat.st_dev == inf[1].stat.st_dev
+ && inf[0].stat.st_size == inf[1].stat.st_size
+ && inf[0].desc != -1
+ && inf[1].desc != -1)
+ && 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;
+ }
+
+ /* 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..e75050f
--- /dev/null
+++ b/gnu/usr.bin/diff/diff.h
@@ -0,0 +1,348 @@
+/* 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 <ctype.h>
+#include <stdio.h>
+#include "regex.h"
+
+#ifndef PR_FILE_NAME
+#define PR_FILE_NAME "/bin/pr"
+#endif
+
+#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 lengths are different.
+ This depends on various options. */
+EXTERN int length_varies;
+
+/* 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;
+
+/* character that ends a line. Currently this is always `\n'. */
+EXTERN char line_end_char;
+
+/* 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;
+
+/* 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 *, size_t, char const *, size_t));
+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/diff3.c b/gnu/usr.bin/diff/diff3.c
new file mode 100644
index 0000000..1ac3887
--- /dev/null
+++ b/gnu/usr.bin/diff/diff3.c
@@ -0,0 +1,1707 @@
+/* Three way file comparison program (diff3) for Project GNU.
+ Copyright (C) 1988, 1989, 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 Randy Smith */
+
+#include "system.h"
+#include <stdio.h>
+#include <ctype.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 *argv0;
+
+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 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 undotlines PARAMS((FILE *, int, int, int));
+static void usage PARAMS((int));
+
+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;
+ 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;
+
+ incompat = 0;
+
+ argv0 = 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 ("GNU diff3 version %s\n", version_string);
+ exit (0);
+ case 129:
+ usage (0);
+ case 'L':
+ /* Handle up to three -L options. */
+ if (tag_count < 3)
+ {
+ tag_strings[tag_count++] = optarg;
+ break;
+ }
+ /* Falls through */
+ default:
+ usage (2);
+ }
+ }
+
+ 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. */
+ || argc - optind != 3)
+ usage (2);
+
+ 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", argv0, file[i]);
+ exit (2);
+ }
+ }
+
+ 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;
+ }
+
+ if (ferror (stdout) || fclose (stdout) != 0)
+ fatal ("write error");
+ exit (conflicts_found);
+ return conflicts_found;
+}
+
+/*
+ * Explain, patiently and kindly, how to use this program. Then exit.
+ */
+static void
+usage (status)
+ int status;
+{
+ fflush (stderr);
+ printf ("\
+Usage: %s [options] my-file older-file your-file\n\
+Options:\n\
+ [-exAEX3aTv] [-i|-m] [-L label1 [-L label2 [-L label3]]]\n\
+ [--easy-only] [--ed] [--help] [--initial-tab]\n\
+ [--label=label1 [--label=label2 [--label=label3]]] [--merge]\n\
+ [--overlap-only] [--show-all] [--show-overlap] [--text] [--version]\n\
+ Only one of [exAEX3] is allowed\n", argv0);
+ exit (status);
+}
+
+/*
+ * 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;
+
+#define DIFF_CHUNK_SIZE 10000
+
+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: ", argv0);
+ 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;
+ char const *argv[7];
+ char horizon_arg[256];
+ char const **ap;
+ int fds[2];
+ pid_t pid;
+ int wstatus;
+
+ 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 failed");
+
+ 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 */
+ current_chunk_size = DIFF_CHUNK_SIZE;
+ diff_result = xmalloc (current_chunk_size);
+ total = 0;
+ do {
+ bytes = myread (fds[0],
+ 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_WAITPID
+ if (waitpid (pid, &wstatus, 0) < 0)
+ perror_with_exit ("waitpid failed");
+#else
+ for (;;) {
+ pid_t w = wait (&wstatus);
+ if (w < 0)
+ perror_with_exit ("wait failed");
+ if (w == pid)
+ break;
+ }
+#endif
+
+ 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, firstchar)
+ char *scan_ptr, **set_start;
+ size_t *set_length;
+ char *limit;
+ char firstchar;
+{
+ char *line_ptr;
+
+ if (!(scan_ptr[0] == (firstchar)
+ && 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:", argv0);
+ 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", argv0, string);
+ exit (2);
+}
+
+static void
+perror_with_exit (string)
+ char const *string;
+{
+ int e = errno;
+ fprintf (stderr, "%s: ", argv0);
+ 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..baadfbf
--- /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 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;
+
+ /* 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;
+
+ d_size = strlen (d_name) + 1;
+ 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 VOID_CLOSEDIR
+ 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 strcmp (* (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 && strcmp (*names0, dir_start_file) < 0)
+ names0++;
+ while (*names1 && strcmp (*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
+ : strcmp (*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/ed.c b/gnu/usr.bin/diff/ed.c
new file mode 100644
index 0000000..717ef35
--- /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/fnmatch.h b/gnu/usr.bin/diff/fnmatch.h
new file mode 100644
index 0000000..55cb17c
--- /dev/null
+++ b/gnu/usr.bin/diff/fnmatch.h
@@ -0,0 +1,62 @@
+/* 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 __P
+#define __P(args) args
+#else /* Not C++ or ANSI C. */
+#undef __P
+#define __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'. */
+#ifndef FNM_PATHNAME
+#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
+#endif
+#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 __P ((const char *__pattern, const char *__string,
+ int __flags));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* fnmatch.h */
diff --git a/gnu/usr.bin/diff/getopt.c b/gnu/usr.bin/diff/getopt.c
new file mode 100644
index 0000000..7a4673b
--- /dev/null
+++ b/gnu/usr.bin/diff/getopt.c
@@ -0,0 +1,757 @@
+/* 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
+#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__
+/* 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.
+ (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 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/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..f784b57
--- /dev/null
+++ b/gnu/usr.bin/diff/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/diff/ifdef.c b/gnu/usr.bin/diff/ifdef.c
new file mode 100644
index 0000000..4e81ef8
--- /dev/null
+++ b/gnu/usr.bin/diff/ifdef.c
@@ -0,0 +1,428 @@
+/* #ifdef-format output routines for GNU DIFF.
+ Copyright (C) 1989, 91, 92, 93 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..95702ba
--- /dev/null
+++ b/gnu/usr.bin/diff/io.c
@@ -0,0 +1,666 @@
+/* File I/O 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. */
+
+#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. */
+typedef int word;
+
+/* 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; /* The length of that line. */
+};
+
+/* Hash-table: array of buckets, each being a chain of equivalence classes. */
+static int *buckets;
+
+/* Number of buckets in the hash table array. */
+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) (size != 0 && 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. */
+ current->buffered_chars = read (current->desc,
+ current->buffer,
+ current->bufsize);
+ if (current->buffered_chars == -1)
+ pfatal_with_name (current->name);
+ return binary_file_p (current->buffer, current->buffered_chars);
+ }
+ }
+
+ 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;
+ char const *incomplete_tail
+ = current->missing_newline && ROBUST_OUTPUT_STYLE (output_style)
+ ? bufend : (char const *) 0;
+ int varies = length_varies;
+
+ 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))
+ {
+ while (isspace (c = *p++))
+ 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))
+ {
+ while (isspace (c = *p++))
+ 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 - ((char const *) p == incomplete_tail);
+ 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
+ && (eqs[i].length == length || varies)
+ && ! line_cmp (eqs[i].line, eqs[i].length, ip, length))
+ /* Reuse existing equivalence class. */
+ 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)
+ {
+ linbuf[line] -= (char const *) p == incomplete_tail;
+ 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 unless -B is in effect. */
+
+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 = ! ignore_blank_lines_flag;
+ }
+
+ /* 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)
+ 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 * sizeof (*buckets));
+ bzero (buckets, nbuckets * 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);
+
+ 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/regex.c b/gnu/usr.bin/diff/regex.c
new file mode 100644
index 0000000..81b06ff
--- /dev/null
+++ b/gnu/usr.bin/diff/regex.c
@@ -0,0 +1,5171 @@
+/* Extended regular expression matching and search library,
+ version 0.12.
+ (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
+
+#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
+
+/* 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 */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+char *realloc ();
+#endif
+
+
+/* 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
+
+/* 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>
+
+/* Jim Meyering writes:
+
+ "... Some ctype macros are valid only for character codes that
+ isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+ using /bin/cc or gcc but without giving an ansi option). So, all
+ ctype uses should be through macros like ISPRINT... If
+ STDC_HEADERS is defined, then autoconf has verified that the ctype
+ macros don't need to be guarded with references to isascii. ...
+ Defining isascii to 1 should let any compiler worth its salt
+ eliminate the && through constant folding." */
+#if ! defined (isascii) || defined (STDC_HEADERS)
+#undef 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 RETALLOC_IF(addr, n, t) \
+ if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), 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)
+ {
+ printf ("%d:\t", p - start);
+
+ 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, last = -100;
+ register int in_range = 0;
+
+ printf ("/charset [%s",
+ (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
+
+ assert (p + *p < pend);
+
+ for (c = 0; c < 256; c++)
+ if (c / 8 < *p
+ && (p[1 + (c/8)] & (1 << (c % 8))))
+ {
+ /* Are we starting a range? */
+ if (last + 1 == c && ! in_range)
+ {
+ putchar ('-');
+ in_range = 1;
+ }
+ /* Have we broken a range? */
+ else if (last + 1 != c && in_range)
+ {
+ printchar (last);
+ in_range = 0;
+ }
+
+ if (! in_range)
+ printchar (c);
+
+ last = c;
+ }
+
+ if (in_range)
+ printchar (last);
+
+ putchar (']');
+
+ 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 to %d", p + mcnt - start);
+ break;
+
+ case on_failure_keep_string_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/on_failure_keep_string_jump to %d", p + mcnt - start);
+ break;
+
+ case dummy_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/dummy_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case push_dummy_failure:
+ printf ("/push_dummy_failure");
+ break;
+
+ case maybe_pop_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/maybe_pop_jump to %d", p + mcnt - start);
+ break;
+
+ case pop_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/pop_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case jump_past_alt:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump_past_alt to %d", p + mcnt - start);
+ break;
+
+ case jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump to %d", p + mcnt - start);
+ break;
+
+ case succeed_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/succeed_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case jump_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/jump_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case set_number_at:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/set_number_at location %d to %d", p + mcnt - start, 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));
+ }
+
+ putchar ('\n');
+ }
+
+ printf ("%d:\tend of pattern.\n", p - start);
+}
+
+
+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 */
+ };
+
+/* Avoiding alloca during matching, to placate r_alloc. */
+
+/* Define MATCH_MAY_ALLOCATE if we need to make sure that the
+ searching and matching functions should not call alloca. On some
+ systems, alloca is implemented in terms of malloc, and if we're
+ using the relocating allocator routines, then malloc could cause a
+ relocation, which might (if the strings being searched are in the
+ ralloc heap) shift the data out from underneath the regexp
+ routines.
+
+ Here's another reason to avoid allocation: Emacs insists on
+ processing input from X in a signal handler; processing X input may
+ call malloc; if input arrives while a matching routine is calling
+ malloc, then we're scrod. But Emacs can't just block input while
+ calling matching routines; then we don't notice interrupts when
+ they come in. So, Emacs blocks input around all regexp calls
+ except the matching calls, which it leaves unprotected, in the
+ faith that they will not malloc. */
+
+/* Normally, this is fine. */
+#define MATCH_MAY_ALLOCATE
+
+/* But under some circumstances, it's not. */
+#if defined (emacs) || (defined (REL_ALLOC) && defined (C_ALLOCA))
+#undef MATCH_MAY_ALLOCATE
+#endif
+
+
+/* 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 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. */
+
+#ifdef MATCH_MAY_ALLOCATE
+#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)
+#else
+#define INIT_FAIL_STACK() \
+ do { \
+ fail_stack.avail = 0; \
+ } while (0)
+#endif
+
+
+/* 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 */
+
+
+
+/* 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)
+
+
+/* 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)
+
+
+
+/* How do we implement a missing MATCH_MAY_ALLOCATE?
+ We make the fail stack a global thing, and then grow it to
+ re_max_failures when we compile. */
+#ifndef MATCH_MAY_ALLOCATE
+static fail_stack_type fail_stack;
+
+static const char ** regstart, ** regend;
+static const char ** old_regstart, ** old_regend;
+static const char **best_regstart, **best_regend;
+static register_info_type *reg_info;
+static const char **reg_dummy;
+static register_info_type *reg_info_dummy;
+#endif
+
+
+/* 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 ('.')
+ && zero_times_ok
+ && 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;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+ 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;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+
+ /* 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: \n");
+ print_compiled_pattern (bufp);
+ }
+#endif /* DEBUG */
+
+#ifndef MATCH_MAY_ALLOCATE
+ /* Initialize the failure stack to the largest possible stack. This
+ isn't necessary unless we're trying to avoid calling alloca in
+ the search and match routines. */
+ {
+ int num_regs = bufp->re_nsub + 1;
+
+ /* Since DOUBLE_FAIL_STACK refuses to double only if the current size
+ is strictly greater than re_max_failures, the largest possible stack
+ is 2 * re_max_failures failure points. */
+ fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS);
+ if (fail_stack.stack)
+ fail_stack.stack =
+ (fail_stack_elt_t *) realloc (fail_stack.stack,
+ (fail_stack.size
+ * sizeof (fail_stack_elt_t)));
+ else
+ fail_stack.stack =
+ (fail_stack_elt_t *) malloc (fail_stack.size
+ * sizeof (fail_stack_elt_t));
+
+ /* Initialize some other variables the matcher uses. */
+ RETALLOC_IF (regstart, num_regs, const char *);
+ RETALLOC_IF (regend, num_regs, const char *);
+ RETALLOC_IF (old_regstart, num_regs, const char *);
+ RETALLOC_IF (old_regend, num_regs, const char *);
+ RETALLOC_IF (best_regstart, num_regs, const char *);
+ RETALLOC_IF (best_regend, num_regs, const char *);
+ RETALLOC_IF (reg_info, num_regs, register_info_type);
+ RETALLOC_IF (reg_dummy, num_regs, const char *);
+ RETALLOC_IF (reg_info_dummy, num_regs, register_info_type);
+ }
+#endif
+
+ 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;
+}
+
+/* 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;
+#ifdef MATCH_MAY_ALLOCATE
+ fail_stack_type fail_stack;
+#endif
+#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;
+ 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 ();
+
+/* 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) \
+ ? ((regoff_t) ((ptr) - string1)) \
+ : ((regoff_t) ((ptr) - string2 + size1)))
+
+/* 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 MATCH_MAY_ALLOCATE
+#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 */
+#else
+#define FREE_VARIABLES() /* Do nothing! */
+#endif /* not MATCH_MAY_ALLOCATE */
+
+/* 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. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */
+ fail_stack_type fail_stack;
+#endif
+#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.) */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **regstart, **regend;
+#endif
+
+ /* 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. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **old_regstart, **old_regend;
+#endif
+
+ /* 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. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */
+ register_info_type *reg_info;
+#endif
+
+ /* 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;
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **best_regstart, **best_regend;
+#endif
+
+ /* 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. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **reg_dummy;
+ register_info_type *reg_info_dummy;
+#endif
+
+#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 ();
+
+#ifdef MATCH_MAY_ALLOCATE
+ /* 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;
+ }
+ }
+#if defined (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 */
+#endif /* MATCH_MAY_ALLOCATE */
+
+ /* 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
+ {
+ /* These braces fend off a "empty body in an else-statement"
+ warning under GCC when assert expands to nothing. */
+ 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
+ ? ((regoff_t) (d - string1))
+ : ((regoff_t) (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]
+ = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]);
+ regs->end[mcnt]
+ = (regoff_t) 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.
+ If what follows this loop is a ...+ construct,
+ look at what begins its body, since we will have to
+ match at least one of that. */
+ while (1)
+ {
+ if (p2 + 2 < pend
+ && ((re_opcode_t) *p2 == stop_memory
+ || (re_opcode_t) *p2 == start_memory))
+ p2 += 3;
+ else if (p2 + 6 < pend
+ && (re_opcode_t) *p2 == dummy_failure_jump)
+ p2 += 6;
+ else
+ break;
+ }
+
+ 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 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];
+
+ 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");
+ }
+ }
+ }
+ else if ((re_opcode_t) *p2 == charset)
+ {
+ register unsigned char c
+ = *p2 == (unsigned char) endline ? '\n' : p2[2];
+
+ if ((re_opcode_t) p1[3] == exactn
+ && ! (p2[1] * BYTEWIDTH > p1[4]
+ && (p2[1 + p1[4] / BYTEWIDTH]
+ & (1 << (p1[4] % BYTEWIDTH)))))
+ {
+ 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_not)
+ {
+ int idx;
+ /* We win if the charset_not inside the loop
+ lists every character listed in the charset after. */
+ for (idx = 0; idx < p2[1]; idx++)
+ if (! (p2[2 + idx] == 0
+ || (idx < p1[4]
+ && ((p2[2 + idx] & ~ p1[5 + idx]) == 0))))
+ break;
+
+ if (idx == p2[1])
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
+ }
+ else if ((re_opcode_t) p1[3] == charset)
+ {
+ int idx;
+ /* We win if the charset inside the loop
+ has no overlap with the one after the loop. */
+ for (idx = 0; idx < p2[1] && idx < p1[4]; idx++)
+ if ((p2[2 + idx] & p1[5 + idx]) != 0)
+ break;
+
+ if (idx == p2[1] || idx == p1[4])
+ {
+ 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;
+ preg->used = 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 = re_error_msg[errcode];
+
+ /* POSIX doesn't require that we do anything in this case, but why
+ not be nice. */
+ if (! msg)
+ msg = "Success";
+
+ 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/diff/regex.h b/gnu/usr.bin/diff/regex.h
new file mode 100644
index 0000000..a495005
--- /dev/null
+++ b/gnu/usr.bin/diff/regex.h
@@ -0,0 +1,490 @@
+/* Definitions for data structures and routines for the regular
+ expression library, version 0.12.
+
+ Copyright (C) 1985, 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __REGEXP_LIBRARY_H__
+#define __REGEXP_LIBRARY_H__
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+ <regex.h>. */
+
+#ifdef VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+ should be there. */
+#include <stddef.h>
+#endif
+
+
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* 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 (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions, of course).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+
+ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+ POSIX draft 11.2 says that * etc. in leading positions is undefined.
+ We already implemented a previous draft which made those constructs
+ invalid, though, so we haven't changed the code back. */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+ than the starting range point, as in [z-a], is invalid.
+ If not set, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t re_syntax_options;
+
+/* Define combinations of the above bits for the standard possibilities.
+ (The [[[ comments delimit what gets put into the Texinfo file, so
+ don't delete them!) */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
+ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
+ | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP \
+ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _RE_SYNTAX_POSIX_COMMON \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+ replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow. Some systems
+ (erroneously) define this in other header files, but we want our
+ value, so remove any previous define. */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+#define RE_DUP_MAX ((1 << 15) - 1)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp'). */
+
+/* If this bit is set, then use extended regular expression syntax.
+ If not set, then use basic regular expression syntax. */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+ characters in the string.
+ If not set, then anchors do match at newlines. */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+ If not set, then returns differ between not matching and errors. */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec). */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+ the beginning of the string (presumably because it's not the
+ beginning of a line).
+ If not set, then the beginning-of-line operator does match the
+ beginning of the string. */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line. */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Not implemented. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `no_sub' can be set. After the pattern has been
+ compiled, the `re_nsub' field is available. All other fields are
+ private to the regex routines. */
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+ /* Space that holds the compiled pattern. It is declared as
+ `unsigned char *' because its elements are
+ sometimes used as array indexes. */
+ unsigned char *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t syntax;
+
+ /* Pointer to a fastmap, if any, otherwise zero. re_search uses
+ the fastmap, if there is one, to skip over impossible
+ starting points for matches. */
+ char *fastmap;
+
+ /* Either a translate table to apply to all characters before
+ comparing them, or zero for no translation. The translation
+ is applied to a pattern when it is compiled and to a string
+ when it is matched. */
+ char *translate;
+
+ /* Number of subexpressions found by the compiler. */
+ size_t re_nsub;
+
+ /* Zero if this pattern cannot match the empty string, one else.
+ Well, in truth it's used only in `re_search_2', to see
+ whether or not we should use the fastmap, so we don't set
+ this absolutely perfectly; see `re_compile_fastmap' (the
+ `duplicate' case). */
+ unsigned can_be_null : 1;
+
+ /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+ for `max (RE_NREGS, re_nsub + 1)' groups.
+ If REGS_REALLOCATE, reallocate space if necessary.
+ If REGS_FIXED, use what's there. */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+ unsigned regs_allocated : 2;
+
+ /* Set to zero when `regex_compile' compiles a pattern; set to one
+ by `re_compile_fastmap' if it updates the fastmap. */
+ unsigned fastmap_accurate : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the
+ beginning of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+
+/* search.c (search_buffer) in Emacs needs this one opcode value. It is
+ defined both in `regex.c' and here. */
+#define RE_EXACTN_VALUE 1
+
+/* Type for byte offsets within the string. POSIX mandates this. */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+ `re_match_2' returns information about at least this many registers
+ the first time a `regs' structure is passed. */
+#ifndef RE_NREGS
+#define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers. Aside from the different names than
+ `re_registers', POSIX uses an array of structures, instead of a
+ structure of arrays. */
+typedef struct
+{
+ regoff_t rm_so; /* Byte offset from string's start to substring's start. */
+ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
+} regmatch_t;
+
+/* Declarations for routines. */
+
+/* To avoid duplicating every routine declaration -- once with a
+ prototype (if we are ANSI), and once without (if we aren't) -- we
+ use the following macro to declare argument types. This
+ unfortunately clutters up the declarations a bit, but I think it's
+ worth it. */
+
+#if __STDC__
+
+#define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+#define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+ You can also simply assign to the `re_syntax_options' variable. */
+extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+/* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `re_syntax_options', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+extern const char *re_compile_pattern
+ _RE_ARGS ((const char *pattern, int length,
+ struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+ compiled into BUFFER. Start searching at position START, for RANGE
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->no_sub are nonzero). */
+extern int re_search
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+extern int re_search_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int re_match
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int re_match_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using BUFFER and REGS will use this memory
+ for recording register information. STARTS and ENDS must be
+ allocated with malloc, 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. */
+extern void re_set_registers
+ _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+ unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+/* 4.2 bsd compatibility. */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+
+/* POSIX compatibility. */
+extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
+extern int regexec
+ _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags));
+extern size_t regerror
+ _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
+ size_t errbuf_size));
+extern void regfree _RE_ARGS ((regex_t *preg));
+
+#endif /* not __REGEXP_LIBRARY_H__ */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/gnu/usr.bin/diff/sdiff.c b/gnu/usr.bin/diff/sdiff.c
new file mode 100644
index 0000000..783f101
--- /dev/null
+++ b/gnu/usr.bin/diff/sdiff.c
@@ -0,0 +1,1193 @@
+/* SDIFF -- interactive merge front end to diff
+ Copyright (C) 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. */
+
+/* GNU SDIFF was written by Thomas Lord. */
+
+#include "system.h"
+#include <stdio.h>
+#include <ctype.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
+#define DEFAULT_EDITOR "ed"
+#endif
+
+extern char version_string[];
+static char const *prog;
+static char const *diffbin = DIFF_PROGRAM;
+static char const *edbin = DEFAULT_EDITOR;
+
+static char *tmpname;
+static int volatile tmpmade;
+static pid_t volatile diffpid;
+
+struct line_filter;
+
+static FILE *ck_fdopen PARAMS((int, char const *));
+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((int, char const *, char const *, char const *));
+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 untrapsig PARAMS((int));
+static void usage PARAMS((int));
+
+/* this lossage until the gnu libc conquers the universe */
+#define PVT_tmpdir "/tmp"
+static char *private_tempnam PARAMS((char const *, char const *, int, size_t *));
+static int diraccess PARAMS((char const *));
+static int exists 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}
+};
+
+/* prints usage message and quits */
+static void
+usage (status)
+ int status;
+{
+ printf ("Usage: %s [options] from-file to-file\n", prog);
+ printf ("Options:\n\
+ [-abBdHilstv] [-I regexp] [-o outfile] [-w columns]\n\
+ [--expand-tabs] [--help] [--ignore-all-space] [--ignore-blank-lines]\n\
+ [--ignore-case] [--ignore-matching-lines=regexp]\n\
+ [--ignore-space-change] [--left-column] [--minimal]\n\
+ [--output=outfile] [--speed-large-files] [--suppress-common-lines]\n\
+ [--text] [--version] [--width=columns]\n");
+ exit (status);
+}
+
+static void
+cleanup ()
+{
+ if (0 < diffpid)
+ kill (diffpid, SIGPIPE);
+ 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", prog, msg);
+ exiterr ();
+}
+
+static void
+perror_fatal (msg)
+ char const *msg;
+{
+ int e = errno;
+ checksigs ();
+ fprintf (stderr, "%s: ", prog);
+ 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 FILE *
+ck_fdopen (fd, type)
+ int fd;
+ char const *type;
+{
+ FILE *r = fdopen (fd, type);
+ if (!r)
+ perror_fatal ("fdopen");
+ 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");
+}
+
+#if !HAVE_MEMCHR
+char *
+memchr (s, c, n)
+ char const *s;
+ int c;
+ size_t n;
+{
+ unsigned char const *p = (unsigned char const *) s, *lim = p + n;
+ for (; p < lim; p++)
+ if (*p == c)
+ return (char *) p;
+ return 0;
+}
+#endif
+
+#ifndef HAVE_WAITPID
+/* Emulate waitpid well enough for sdiff, which has at most two children. */
+static pid_t
+waitpid (pid, stat_loc, options)
+ pid_t pid;
+ int *stat_loc;
+ int options;
+{
+ static int ostatus;
+ static pid_t opid;
+ int npid, status;
+
+ if (pid == opid)
+ {
+ opid = 0;
+ status = ostatus;
+ }
+ else
+ while ((npid = wait (&status)) != pid)
+ {
+ if (npid < 0)
+ return npid;
+ opid = npid;
+ ostatus = status;
+ }
+ *stat_loc = status;
+ return pid;
+}
+#endif
+
+static char const *
+expand_name (name, isdir, other_name)
+ char *name;
+ int isdir;
+ char const *other_name;
+{
+ if (strcmp (name, "-") == 0)
+ fatal ("cannot interactively merge standard input");
+ if (!isdir)
+ return name;
+ else
+ {
+ /* Yield NAME/BASE, where BASE is OTHER_NAME's basename. */
+ char const
+ *p = strrchr (other_name, '/'),
+ *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 = getenv ("EDITOR");
+ char *differ = getenv ("DIFF");
+
+ prog = argv[0];
+ if (editor)
+ edbin = editor;
+ 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 ("GNU sdiff version %s\n", version_string);
+ exit (0);
+
+ case 'w':
+ diffarg ("-W");
+ diffarg (optarg);
+ break;
+
+ case 'W':
+ diffarg ("-w");
+ break;
+
+ case 129:
+ usage (0);
+
+ default:
+ usage (2);
+ }
+ }
+
+ if (argc - optind != 2)
+ usage (2);
+
+ if (! out_file)
+ /* easy case: diff does everything for us */
+ execdiff (suppress_common_flag, "-y", argv[optind], argv[optind + 1]);
+ else
+ {
+ FILE *left, *right, *out, *diffout;
+ int diff_fds[2];
+ int interact_ok;
+ pid_t pid;
+ 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");
+
+ if (pipe (diff_fds))
+ perror_fatal ("pipe");
+
+ trapsigs ();
+
+ diffpid = pid = vfork ();
+
+ if (pid == 0)
+ {
+ 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 (0, "--sdiff-merge-assist", argv[optind], argv[optind + 1]);
+ }
+
+ if (pid < 0)
+ perror_fatal ("fork failed");
+
+ close (diff_fds[1]);
+ diffout = ck_fdopen (diff_fds[0], "r");
+
+ lf_init (&diff_filt, diffout);
+ lf_init (&lfilt, left);
+ lf_init (&rfilt, right);
+
+ interact_ok = interact (&diff_filt, &lfilt, &rfilt, out);
+
+ ck_fclose (diffout);
+ ck_fclose (left);
+ ck_fclose (right);
+ ck_fclose (out);
+
+ {
+ int wstatus;
+
+ while (waitpid (pid, &wstatus, 0) < 0)
+ if (errno == EINTR)
+ checksigs ();
+ else
+ perror_fatal ("wait failed");
+ diffpid = 0;
+
+ 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 char const **diffargv;
+
+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 (differences_only, option, file1, file2)
+ int differences_only;
+ char const *option, *file1, *file2;
+{
+ if (differences_only)
+ diffarg ("--suppress-common-lines");
+ diffarg (option);
+ diffarg ("--");
+ diffarg (file1);
+ diffarg (file2);
+ diffarg (0);
+
+ 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 */
+ 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;
+ while (isspace (c = getchar ()) && c != '\n')
+ 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 (0, "sdiff", 1, 0)))
+ 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);
+
+ {
+ pid_t pid;
+ int wstatus;
+
+ 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;
+
+ if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 1))
+ 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);
+}
+
+/* Return nonzero if FILE exists. */
+static int
+exists (file)
+ char const *file;
+{
+ struct stat buf;
+ return stat (file, &buf) == 0;
+}
+
+/* These are the characters used in temporary filenames. */
+static char const letters[] =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+/* Generate a temporary filename.
+ If DIR_SEARCH is nonzero, DIR and PFX are used as
+ described for tempnam. If not, a temporary filename
+ in P_tmpdir with no special prefix is generated. If LENPTR
+ is not 0, *LENPTR is set the to length (including the
+ terminating '\0') of the resultant filename, which is returned.
+ 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'. Data for tempnam and tmpnam
+ is kept separate, but when tempnam is using P_tmpdir and no
+ prefix (i.e, it is identical to tmpnam), the same data is used.
+ 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 (12345ZZZ), 0 is returned. */
+
+
+static char *
+private_tempnam (dir, pfx, dir_search, lenptr)
+ char const *dir;
+ char const *pfx;
+ int dir_search;
+ size_t *lenptr;
+{
+ static char const tmpdir[] = PVT_tmpdir;
+ static struct
+ {
+ char buf[3];
+ char *s;
+ size_t i;
+ } infos[2], *info;
+ static char *buf;
+ static size_t bufsize = 1;
+ static pid_t oldpid = 0;
+ pid_t pid = getpid ();
+ register size_t len, plen;
+
+ if (dir_search)
+ {
+ register char const *d = getenv ("TMPDIR");
+ if (d && !diraccess (d))
+ d = 0;
+ if (!d && dir && diraccess (dir))
+ d = dir;
+ if (!d && diraccess (tmpdir))
+ d = tmpdir;
+ if (!d && diraccess ("/tmp"))
+ d = "/tmp";
+ if (!d)
+ {
+ errno = ENOENT;
+ return 0;
+ }
+ dir = d;
+ }
+ else
+ dir = tmpdir;
+
+ if (pfx && *pfx)
+ {
+ plen = strlen (pfx);
+ if (plen > 5)
+ plen = 5;
+ }
+ else
+ plen = 0;
+
+ if (dir != tmpdir && !strcmp (dir, tmpdir))
+ dir = tmpdir;
+ info = &infos[(plen == 0 && dir == tmpdir) ? 1 : 0];
+
+ if (pid != oldpid)
+ {
+ oldpid = pid;
+ info->buf[0] = info->buf[1] = info->buf[2] = '0';
+ info->s = &info->buf[0];
+ info->i = 0;
+ }
+
+ len = strlen (dir) + 1 + plen + 8;
+ if (bufsize <= len)
+ {
+ do
+ {
+ bufsize *= 2;
+ }
+ while (bufsize <= len);
+
+ if (buf)
+ free (buf);
+ buf = xmalloc (bufsize);
+ }
+ for (;;)
+ {
+ *info->s = letters[info->i];
+ sprintf (buf, "%s/%.*s%.5lu%.3s", dir, (int) plen, pfx,
+ (unsigned long) pid % 100000, info->buf);
+ if (!exists (buf))
+ break;
+ ++info->i;
+ if (info->i > sizeof (letters) - 1)
+ {
+ info->i = 0;
+ if (info->s == &info->buf[2])
+ {
+ errno = EEXIST;
+ return 0;
+ }
+ ++info->s;
+ }
+ }
+
+ if (lenptr)
+ *lenptr = len;
+ return buf;
+}
diff --git a/gnu/usr.bin/diff/side.c b/gnu/usr.bin/diff/side.c
new file mode 100644
index 0000000..9e03c27
--- /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..2da6247
--- /dev/null
+++ b/gnu/usr.bin/diff/system.h
@@ -0,0 +1,215 @@
+/* System dependent declarations.
+ 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. */
+
+/* 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
+
+#ifndef S_IXOTH
+#define S_IXOTH 1
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP (S_IXOTH << 3)
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR (S_IXGRP << 3)
+#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
+#include <sys/file.h>
+#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
+#ifndef _POSIX_VERSION
+/* Prevent the NeXT prototype using union wait from causing problems. */
+#define wait system_wait
+#endif
+#include <sys/wait.h>
+#ifndef _POSIX_VERSION
+#undef wait
+#endif
+#endif /* HAVE_SYS_WAIT_H */
+
+#ifndef WEXITSTATUS
+#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) == 0)
+#endif
+
+#if HAVE_ST_BLKSIZE
+#define STAT_BLOCKSIZE(s) (s).st_blksize
+#else
+#define STAT_BLOCKSIZE(s) (8 * 1024)
+#endif
+
+#if DIRENT || defined (_POSIX_VERSION)
+#include <dirent.h>
+#else /* ! (DIRENT || defined (_POSIX_VERSION)) */
+#if SYSNDIR
+#include <sys/ndir.h>
+#else
+#if SYSDIR
+#include <sys/dir.h>
+#else
+#include <ndir.h>
+#endif
+#endif
+#ifdef dirent
+#undef dirent
+#endif
+#define dirent direct
+#endif /* ! (DIRENT || defined (_POSIX_VERSION)) */
+
+#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 HAVE_STRING_H
+#include <string.h>
+#ifndef bzero
+#define bzero(s,n) memset (s,0,n)
+#endif
+#else /* !HAVE_STRING_H */
+#include <strings.h>
+#ifndef strchr
+#define strchr index
+#endif
+#ifndef strrchr
+#define strrchr rindex
+#endif
+#ifndef memcpy
+#define memcpy(d,s,n) bcopy (s,d,n)
+#endif
+#ifndef memcmp
+#define memcmp(s1,s2,n) bcmp (s1,s2,n)
+#endif
+#endif /* !HAVE_STRING_H */
+#if !HAVE_MEMCHR
+char *memchr ();
+#endif
+
+#include <errno.h>
+#if !STDC_HEADERS
+extern int errno;
+#endif
+
+#define min(a,b) ((a) <= (b) ? (a) : (b))
+#define max(a,b) ((a) >= (b) ? (a) : (b))
diff --git a/gnu/usr.bin/diff/util.c b/gnu/usr.bin/diff/util.c
new file mode 100644
index 0000000..38e20f4
--- /dev/null
+++ b/gnu/usr.bin/diff/util.c
@@ -0,0 +1,744 @@
+/* Support routines 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. */
+
+#include "diff.h"
+
+/* 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);
+ 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);
+ 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);
+ 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;
+}
+
+static pid_t pr_pid;
+
+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 are some
+ bugs 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,
+ and it requires two spaces after "diff" if there are no options.
+ These requirements are silly and do not match historical practice. */
+ sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1);
+
+ if (paginate_flag)
+ {
+ int pipes[2];
+
+ /* Fork a `pr' and make OUTFILE a pipe to it. */
+ 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_FILE_NAME, PR_FILE_NAME, "-f", "-h", name, 0);
+ pfatal_with_name (PR_FILE_NAME);
+ }
+ else
+ {
+ close (pipes[0]);
+ outfile = fdopen (pipes[1], "w");
+ }
+ }
+ 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 (fclose (outfile) != 0)
+ pfatal_with_name ("write error");
+#if HAVE_WAITPID
+ if (waitpid (pr_pid, &wstatus, 0) < 0)
+ pfatal_with_name ("waitpid");
+#else
+ for (;;) {
+ pid_t w = wait (&wstatus);
+ if (w < 0)
+ pfatal_with_name ("wait");
+ if (w == pr_pid)
+ break;
+ }
+#endif
+ if (! WIFEXITED (wstatus) || WEXITSTATUS (wstatus) != 0)
+ fatal ("subsidiary pr failed");
+ }
+
+ outfile = 0;
+}
+
+/* Compare two lines (typically one from each input file)
+ according to the command line options.
+ Return 1 if the lines differ, like `memcmp'. */
+
+int
+line_cmp (s1, len1, s2, len2)
+ char const *s1, *s2;
+ size_t len1, len2;
+{
+ register unsigned char const *t1, *t2;
+ register unsigned char end_char = line_end_char;
+
+ /* Check first for exact identity.
+ If that is true, return 0 immediately.
+ This detects the common case of exact identity
+ faster than complete comparison would. */
+
+ if (len1 == len2 && memcmp (s1, s2, len1) == 0)
+ return 0;
+
+ /* Not exactly identical, but perhaps they match anyway
+ when case or white space is ignored. */
+
+ if (ignore_case_flag | ignore_space_change_flag | ignore_all_space_flag)
+ {
+ t1 = (unsigned char const *) s1;
+ t2 = (unsigned char const *) s2;
+
+ while (1)
+ {
+ register unsigned char c1 = *t1++;
+ register unsigned char c2 = *t2++;
+
+ /* 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 != end_char) c1 = *t1++;
+ while (isspace (c2) && c2 != end_char) 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 != end_char)
+ {
+ c1 = *t1++;
+ if (! isspace (c1))
+ {
+ --t1;
+ c1 = ' ';
+ break;
+ }
+ }
+ }
+
+ /* Likewise for line 2. */
+ if (isspace (c2))
+ {
+ while (c2 != end_char)
+ {
+ c2 = *t2++;
+ if (! isspace (c2))
+ {
+ --t2;
+ c2 = ' ';
+ break;
+ }
+ }
+ }
+ }
+
+ /* Upcase all letters if -i is specified. */
+
+ if (ignore_case_flag)
+ {
+ if (islower (c1))
+ c1 = toupper (c1);
+ if (islower (c2))
+ c2 = toupper (c2);
+ }
+
+ if (c1 != c2)
+ break;
+ if (c1 == end_char)
+ 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'
+ && line_end_char == '\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)
+ char 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;
+{
+ return concat (dir, "/" + (*dir && dir[strlen (dir) - 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);
+}
+
+#if !HAVE_MEMCHR
+char *
+memchr (s, c, n)
+ char const *s;
+ int c;
+ size_t n;
+{
+ unsigned char const *p = (unsigned char const *) s, *lim = p + n;
+ for (; p < lim; p++)
+ if (*p == c)
+ return (char *) p;
+ return 0;
+}
+#endif
diff --git a/gnu/usr.bin/diff/version.c b/gnu/usr.bin/diff/version.c
new file mode 100644
index 0000000..234ec29
--- /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.6";
diff --git a/gnu/usr.bin/diff3/COPYING b/gnu/usr.bin/diff3/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/gnu/usr.bin/diff3/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/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..b190328
--- /dev/null
+++ b/gnu/usr.bin/diff3/diff3.1
@@ -0,0 +1,207 @@
+.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 \-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/diff3/diff3.c b/gnu/usr.bin/diff3/diff3.c
new file mode 100644
index 0000000..b9952fc
--- /dev/null
+++ b/gnu/usr.bin/diff3/diff3.c
@@ -0,0 +1,1693 @@
+/* Three way file comparison program (diff3) for Project GNU.
+ Copyright (C) 1988, 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. */
+
+/* Written by Randy Smith */
+
+#if __STDC__
+#define VOID void
+#else
+#define VOID char
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include "getopt.h"
+#include "system.h"
+
+/*
+ * 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) */
+ int *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) */
+ int *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;
+
+/* 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 *argv0;
+
+/*
+ * Forward function declarations.
+ */
+static int myread ();
+static void fatal ();
+static void perror_with_exit ();
+static struct diff_block *process_diff ();
+static struct diff3_block *make_3way_diff ();
+static void output_diff3 ();
+static int output_diff3_edscript ();
+static int output_diff3_merge ();
+static void usage ();
+
+static struct diff3_block *using_to_diff3_block ();
+static int copy_stringlist ();
+static struct diff3_block *create_diff3_block ();
+static int compare_line_list ();
+
+static char *read_diff ();
+static enum diff_type process_diff_control ();
+static char *scan_diff_line ();
+
+static struct diff3_block *reverse_diff3_blocklist ();
+
+VOID *xmalloc ();
+static VOID *xrealloc ();
+
+static char diff_program[] = DIFF_PROGRAM;
+
+static struct option longopts[] =
+{
+ {"text", 0, NULL, 'a'},
+ {"show-all", 0, NULL, 'A'},
+ {"ed", 0, NULL, 'e'},
+ {"show-overlap", 0, NULL, 'E'},
+ {"label", 1, NULL, 'L'},
+ {"merge", 0, NULL, 'm'},
+ {"overlap-only", 0, NULL, 'x'},
+ {"easy-only", 0, NULL, '3'},
+ {"version", 0, NULL, 'v'},
+ {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;
+{
+ extern char *version_string;
+ int c, i;
+ int mapping[3];
+ int rev_mapping[3];
+ int incompat;
+ int conflicts_found;
+ struct diff_block *thread0, *thread1, *last_block;
+ struct diff3_block *diff3;
+ int tag_count = 0;
+ char *tag_strings[3];
+ extern char *optarg;
+ char *commonname;
+ char **file;
+ struct stat statb;
+
+ incompat = 0;
+
+ argv0 = argv[0];
+
+ while ((c = getopt_long (argc, argv, "aeimvx3AEXL:", longopts, (int *) 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 'v':
+ fprintf (stderr, "GNU diff3 version %s\n", version_string);
+ break;
+ case 'L':
+ /* Handle up to three -L options. */
+ if (tag_count < 3)
+ {
+ tag_strings[tag_count++] = optarg;
+ break;
+ }
+ /* Falls through */
+ default:
+ usage ();
+ /* NOTREACHED */
+ }
+ }
+
+ 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. */
+ || argc - optind != 3)
+ usage ();
+
+ 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", argv0, file[i]);
+ exit (2);
+ }
+
+
+ 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;
+ }
+
+ if (ferror (stdout) || fclose (stdout) != 0)
+ fatal ("write error");
+ exit (conflicts_found);
+ return conflicts_found;
+}
+
+/*
+ * Explain, patiently and kindly, how to use this program. Then exit.
+ */
+static void
+usage ()
+{
+ fprintf (stderr, "\
+Usage: %s [options] my-file older-file your-file\n\
+Options:\n\
+ [-exAEX3v] [-i|-m] [-L label1 [-L label2 [-L label3]]] [--text] [--ed]\n\
+ [--merge] [--show-all] [--show-overlap] [--overlap-only] [--easy-only]\n\
+ [--label=label1 [--label=label2 [--label=label3]]] [--version]\n\
+ Only one of [exAEX3] is allowed\n", argv0);
+ exit (2);
+}
+
+/*
+ * 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 bcmp'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 bcmp's (if a
+ * bcmp 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,
+ *last_diff3;
+
+ static struct diff3_block zero_diff3 = {
+ ERROR,
+ { {0, 0}, {0, 0}, {0, 0} },
+ { (char **) 0, (char **) 0, (char **) 0 },
+ { (int *) 0, (int *) 0, (int *) 0 },
+ (struct diff3_block *) 0
+ };
+
+ /* 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] =
+ (struct diff_block *) 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
+ = (struct diff_block *) 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
+ = (struct diff_block *) 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 *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 *fromptrs[], *toptrs[];
+ int *fromlengths, *tolengths;
+ int copynum;
+{
+ register char
+ **f = fromptrs,
+ **t = toptrs;
+ register int
+ *fl = fromlengths,
+ *tl = tolengths;
+
+ while (copynum--)
+ {
+ if (*t)
+ { if (*fl != *tl || bcmp (*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, int);
+ bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *)));
+ bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (int)));
+ }
+ else
+ {
+ D_LINEARRAY (result, FILE0) = (char **) 0;
+ D_LENARRAY (result, FILE0) = (int *) 0;
+ }
+
+ numlines = D_NUMLINES (result, FILE1);
+ if (numlines)
+ {
+ D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *);
+ D_LENARRAY (result, FILE1) = ALLOCATE (numlines, int);
+ bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *)));
+ bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (int)));
+ }
+ else
+ {
+ D_LINEARRAY (result, FILE1) = (char **) 0;
+ D_LENARRAY (result, FILE1) = (int *) 0;
+ }
+
+ numlines = D_NUMLINES (result, FILE2);
+ if (numlines)
+ {
+ D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *);
+ D_LENARRAY (result, FILE2) = ALLOCATE (numlines, int);
+ bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *)));
+ bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (int)));
+ }
+ else
+ {
+ D_LINEARRAY (result, FILE2) = (char **) 0;
+ D_LENARRAY (result, FILE2) = (int *) 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 *list1[], *list2[];
+ int *lengths1, *lengths2;
+ int nl;
+{
+ char
+ **l1 = list1,
+ **l2 = list2;
+ int
+ *lgths1 = lengths1,
+ *lgths2 = lengths2;
+
+ while (nl--)
+ if (!*l1 || !*l2 || *lgths1 != *lgths2++
+ || bcmp (*l1++, *l2++, *lgths1++))
+ return 0;
+ return 1;
+}
+
+/*
+ * Routines to input and parse two way diffs.
+ */
+
+extern char **environ;
+
+#define DIFF_CHUNK_SIZE 10000
+
+static struct diff_block *
+process_diff (filea, fileb, last_block)
+ char *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;
+
+ while (scan_diff < diff_limit)
+ {
+ bptr = ALLOCATE (1, struct diff_block);
+ bptr->lines[0] = bptr->lines[1] = (char **) 0;
+ bptr->lengths[0] = bptr->lengths[1] = (int *) 0;
+
+ dt = process_diff_control (&scan_diff, bptr);
+ if (dt == ERROR || *scan_diff != '\n')
+ {
+ fprintf (stderr, "%s: diff error: ", argv0);
+ 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, int);
+ 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, int);
+ 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) \
+ { if (!isdigit (*s)) return ERROR; holdnum = 0; \
+ do { holdnum = (*s++ - '0' + holdnum * 10); } \
+ while (isdigit (*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 *filea, *fileb;
+ char **output_placement;
+{
+ char *argv[7];
+ char horizon_arg[256];
+ char **ap;
+ int fds[2];
+ char *diff_result;
+ int current_chunk_size;
+ int bytes;
+ int total;
+ int pid, w;
+ int wstatus;
+
+ 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 = (char *) 0;
+
+ if (pipe (fds) < 0)
+ perror_with_exit ("pipe failed");
+
+ pid = vfork ();
+ if (pid == 0)
+ {
+ /* Child */
+ close (fds[0]);
+ if (fds[1] != fileno (stdout))
+ {
+ dup2 (fds[1], fileno (stdout));
+ close (fds[1]);
+ }
+ execve (diff_program, argv, environ);
+ /* Avoid stdio, because the parent process's buffers are inherited. */
+ write (fileno (stderr), diff_program, strlen (diff_program));
+ write (fileno (stderr), ": not found\n", 12);
+ _exit (2);
+ }
+
+ if (pid == -1)
+ perror_with_exit ("fork failed");
+
+ close (fds[1]); /* Prevent erroneous lack of EOF */
+ current_chunk_size = DIFF_CHUNK_SIZE;
+ diff_result = (char *) xmalloc (current_chunk_size);
+ total = 0;
+ do {
+ bytes = myread (fds[0],
+ diff_result + total,
+ current_chunk_size - total);
+ total += bytes;
+ if (total == current_chunk_size)
+ diff_result = (char *) 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;
+
+ do
+ if ((w = wait (&wstatus)) == -1)
+ perror_with_exit ("wait failed");
+ while (w != pid);
+
+ 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, firstchar)
+ char *scan_ptr, **set_start;
+ int *set_length;
+ char *limit;
+ char firstchar;
+{
+ char *line_ptr;
+
+ if (!(scan_ptr[0] == (firstchar)
+ && 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:", argv0);
+ 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 mapping[3], rev_mapping[3];
+{
+ int i;
+ int oddoneout;
+ char *cp;
+ struct diff3_block *ptr;
+ int line;
+ int length;
+ int dontprint;
+ static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
+
+ 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;
+
+ for (line = 0; line < hight - lowt + 1; line++)
+ {
+ fprintf (outputfile, " ");
+ cp = D_RELNUM (ptr, realfile, line);
+ length = D_RELLEN (ptr, realfile, line);
+ fwrite (cp, sizeof (char), length, outputfile);
+ }
+ if (line != 0 && 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 mapping[3], rev_mapping[3];
+ char *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 mapping[3], rev_mapping[3];
+ char *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 *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 = (struct diff3_block *) 0;
+ tmp; tmp = next)
+ {
+ next = tmp->next;
+ tmp->next = prev;
+ prev = tmp;
+ }
+
+ return prev;
+}
+
+static int
+myread (fd, ptr, size)
+ int fd, size;
+ char *ptr;
+{
+ int result = read (fd, ptr, size);
+ if (result < 0)
+ perror_with_exit ("read failed");
+ return result;
+}
+
+VOID *
+xmalloc (size)
+ unsigned size;
+{
+ VOID *result = (VOID *) malloc (size ? size : 1);
+ if (!result)
+ fatal ("virtual memory exhausted");
+ return result;
+}
+
+static VOID *
+xrealloc (ptr, size)
+ VOID *ptr;
+ unsigned size;
+{
+ VOID *result = (VOID *) realloc (ptr, size ? size : 1);
+ if (!result)
+ fatal ("virtual memory exhausted");
+ return result;
+}
+
+static void
+fatal (string)
+ char *string;
+{
+ fprintf (stderr, "%s: %s\n", argv0, string);
+ exit (2);
+}
+
+static void
+perror_with_exit (string)
+ char *string;
+{
+ int e = errno;
+ fprintf (stderr, "%s: ", argv0);
+ errno = e;
+ perror (string);
+ exit (2);
+}
diff --git a/gnu/usr.bin/diff3/getopt.c b/gnu/usr.bin/diff3/getopt.c
new file mode 100644
index 0000000..a59a013
--- /dev/null
+++ b/gnu/usr.bin/diff3/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/diff3/getopt.h b/gnu/usr.bin/diff3/getopt.h
new file mode 100644
index 0000000..45541f5
--- /dev/null
+++ b/gnu/usr.bin/diff3/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/diff3/getopt1.c b/gnu/usr.bin/diff3/getopt1.c
new file mode 100644
index 0000000..a32615c
--- /dev/null
+++ b/gnu/usr.bin/diff3/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/diff3/system.h b/gnu/usr.bin/diff3/system.h
new file mode 100644
index 0000000..b17d39a
--- /dev/null
+++ b/gnu/usr.bin/diff3/system.h
@@ -0,0 +1,159 @@
+/* System dependent declarations.
+ 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. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#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 HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if HAVE_TIME_H
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#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
+#ifndef _POSIX_VERSION
+/* Prevent the NeXT prototype using union wait from causing problems. */
+#define wait system_wait
+#endif
+#include <sys/wait.h>
+#ifndef _POSIX_VERSION
+#undef wait
+#endif
+#endif /* HAVE_SYS_WAIT_H */
+
+#ifndef WEXITSTATUS
+#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) == 0)
+#endif
+
+#if HAVE_ST_BLKSIZE
+#define STAT_BLOCKSIZE(s) (s).st_blksize
+#else
+#define STAT_BLOCKSIZE(s) (S_ISREG ((s).st_mode) ? 8192 : 4096)
+#endif
+
+#if DIRENT || defined (_POSIX_VERSION)
+#include <dirent.h>
+#ifdef direct
+#undef direct
+#endif
+#define direct dirent
+#else /* ! (DIRENT || defined (_POSIX_VERSION)) */
+#if SYSNDIR
+#include <sys/ndir.h>
+#else
+#if SYSDIR
+#include <sys/dir.h>
+#else
+#include <ndir.h>
+#endif
+#endif
+#endif /* ! (DIRENT || defined (_POSIX_VERSION)) */
+
+#if HAVE_VFORK_H
+#include <vfork.h>
+#endif
+
+#if HAVE_STRING_H || STDC_HEADERS
+#include <string.h>
+#ifndef index
+#define index strchr
+#endif
+#ifndef rindex
+#define rindex strrchr
+#endif
+#ifndef bcopy
+#define bcopy(s,d,n) memcpy (d,s,n)
+#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
+#if !HAVE_MEMCHR && !STDC_HEADERS
+char *memchr ();
+#endif
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <limits.h>
+#else
+char *getenv ();
+char *malloc ();
+char *realloc ();
+#if __STDC__ || __GNUC__
+#include "limits.h"
+#else
+#define INT_MAX 2147483647
+#define CHAR_BIT 8
+#endif
+#endif
+
+#include <errno.h>
+#if !STDC_HEADERS
+extern int errno;
+#endif
+
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+#define TRUE 1
+#define FALSE 0
+
+#if !__STDC__
+#define volatile
+#endif
+
+#define min(a,b) ((a) <= (b) ? (a) : (b))
+#define max(a,b) ((a) >= (b) ? (a) : (b))
diff --git a/gnu/usr.bin/diff3/version.c b/gnu/usr.bin/diff3/version.c
new file mode 100644
index 0000000..cb9d3b9
--- /dev/null
+++ b/gnu/usr.bin/diff3/version.c
@@ -0,0 +1,3 @@
+/* Version number of GNU diff. */
+
+char *version_string = "2.3";
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/ChangeLog b/gnu/usr.bin/gdb/ChangeLog
new file mode 100644
index 0000000..1f2342b
--- /dev/null
+++ b/gnu/usr.bin/gdb/ChangeLog
@@ -0,0 +1,4887 @@
+Thu Feb 8 01:11:55 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * GDB 3.5 released.
+
+ * version.c: Change version number to 3.5
+
+Tue Feb 6 15:58:06 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * m-hp9k320.h: define ATTACH_DETACH.
+ hp9k320-dep.c [ATTACH_DETACH]: New code.
+
+Thu Feb 1 17:43:00 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * valprint.c (is_nan, val_print): Use char * not void *.
+
+ * symmisc.c (print_symbol): Print newline after label.
+
+Tue Jan 30 15:35:52 1990 Jim Kingdon (kingdon at albert.ai.mit.edu)
+
+ * Makefile.dist (READLINE): Add {readline,history}.texinfo.
+
+ * m-merlin.h: Put in clarifying comments about SHELL_FILE.
+ config.gdb (merlin): Explain about /usr/local/lib/gdb-sh.
+
+Sat Jan 27 02:30:27 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * version.c: Change version number to 3.5alpha.1.
+
+ * dbxread.c (process_one_symbol): Compare context_stack_depth
+ with !VARIABLES_INSIDE_BLOCK, not VARIABLES_INSIDE_BLOCK.
+
+Fri Jan 26 01:21:51 1990 Jim Kingdon (kingdon at mole.ai.mit.edu)
+
+ * main.c [ALIGN_STACK_ON_STARTUP]: New code.
+ m-i386.h: Define ALIGN_STACK_ON_STARTUP.
+
+ * m-merlin.h (NO_SIGINTERRUPT, SHELL_FILE): Define.
+
+ * umax-dep.c (exec_file_command): Add commas to call to
+ read_section_hdr.
+
+Tue Jan 23 15:49:47 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * dbxread.c (define_symbol): Deal with deftype 'X'.
+
+ * convex-dep.c (wait): Make it pid_t.
+
+ * convex-dep.c (comm_registers_info): accept decimal comm register
+ specification, as "i comm 32768".
+
+ * dbxread.c (process_one_symbol): Make VARIABLES_INSIDE_BLOCK
+ macro say by itself where variables are. Pass it desc.
+ m-convex.h (VARIABLES_INSIDE_BLOCK): Nonzero for native compiler.
+
+ * m-convex.h (SET_STACK_LIMIT_HUGE): Define.
+ (IGNORE_SYMBOL): Take out #ifdef N_MONPT and put in 0xc4.
+
+Fri Jan 19 20:04:15 1990 Jim Kingdon (kingdon at albert.ai.mit.edu)
+
+ * printcmd.c (print_frame_args): Always set highest_offset to
+ current_offset when former is -1.
+
+ * dbxread.c (read_struct_type): Print nice error message
+ when encountering multiple inheritance.
+
+Thu Jan 18 13:43:30 1990 Jim Kingdon (kingdon at mole.ai.mit.edu)
+
+ * dbxread.c (read_dbx_symtab): Always treat N_FN as a potential
+ source for a x.o or -lx symbol, ignoring OFILE_FN_FLAGGED.
+
+ * printcmd.c (print_frame_args): Cast -1 to (CORE_ADDR).
+
+ * hp300bsd-dep.c (_initialize_hp300_dep): Get kernel_u_addr.
+ m-hp300bsd.h (KERNEL_U_ADDR): Use kernel_u_addr.
+
+ * infcmd.c (run_command): #if 0 out call to
+ breakpoint_clear_ignore_counts.
+
+Thu Jan 11 12:58:12 1990 Jim Kingdon (kingdon at mole)
+
+ * printcmd.c (print_frame_args) [STRUCT_ARG_SYM_GARBAGE]:
+ Try looking up name of var before giving up & printing '?'.
+
+Wed Jan 10 14:00:14 1990 Jim Kingdon (kingdon at pogo)
+
+ * many files: Move stdio.h before param.h.
+
+ * sun3-dep.c (store_inferior_registers): Only try to write FP
+ regs #ifdef FP0_REGNUM.
+
+Mon Jan 8 17:56:15 1990 Jim Kingdon (kingdon at pogo)
+
+ * symtab.c: #if 0 out "info methods" code.
+
+Sat Jan 6 12:33:04 1990 Jim Kingdon (kingdon at pogo)
+
+ * dbxread.c (read_struct_type): Set TYPE_NFN_FIELDS_TOTAL
+ from all baseclasses; remove vestigial variable baseclass.
+
+ * findvar.c (read_var_value): Check REG_STRUCT_HAS_ADDR.
+ printcmd.c (print_frame_args): Check STRUCT_ARG_SYM_GARBAGE.
+ m-sparc.h: Define REG_STRUCT_HAS_ADDR and STRUCT_ARG_SYM_GARBAGE.
+
+ * blockframe.c (get_frame_block): Subtract one from pc if not
+ innermost frame.
+
+Fri Dec 29 15:26:33 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * printcmd.c (print_frame_args): check highest_offset != -1, not i.
+
+Thu Dec 28 16:21:02 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * valops.c (value_struct_elt): Clean up error msg.
+
+ * breakpoint.c (describe_other_breakpoints):
+ Delete extra space before "also set at" and add period at end.
+
+Tue Dec 19 10:28:42 1989 Jim Kingdon (kingdon at pogo)
+
+ * source.c (print_source_lines): Tell user which line number
+ was out of range when printing error message.
+
+Sun Dec 17 14:14:09 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * blockframe.c (find_pc_partial_function): Use
+ BLOCK_START (SYMBOL_BLOCK_VALUE (f)) instead of
+ SYMBOL_VALUE (f) to get start of function.
+
+ * dbxread.c: Make xxmalloc just a #define for xmalloc.
+
+Thu Dec 14 16:13:16 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * m68k-opcode.h (fseq & following fp instructions):
+ Change @ to $.
+
+Fri Dec 8 19:06:44 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * breakpoint.c (breakpoint_clear_ignore_counts): New function.
+ infcmd.c (run_command): Call it.
+
+Wed Dec 6 15:03:38 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * valprint.c: Change it so "array-max 0" means there is
+ no limit.
+
+ * expread.y (yylex): Change error message "invalid token in
+ expression" to "invalid character '%c' in expression".
+
+Mon Dec 4 16:12:54 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * blockframe.c (find_pc_partial_function): Always return 1
+ for success, 0 for failure, and set *NAME and *ADDRESS to
+ match the return value.
+
+ * dbxread.c (symbol_file_command): Use perror_with_name on
+ error from stat.
+ (psymtab_to_symtab, add_file_command),
+ core.c (validate_files), source.c (find_source_lines),
+ default-dep.c (exec_file_command): Check for errors from stat,
+ fstat, and myread.
+
+Fri Dec 1 05:16:42 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * valops.c (check_field): When following pointers, just get
+ their types; don't call value_ind.
+
+Thu Nov 30 14:45:29 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * config.gdb (pyr): New machine.
+ core.c [REG_STACK_SEGMENT]: New code.
+ dbxread.c (process_one_symbol): Cast return from copy_pending
+ to long before casting to enum namespace.
+ infrun.c: Split registers_info into DO_REGISTERS_INFO
+ and registers_info.
+ m-pyr.h, pyr-{dep.c,opcode.h,pinsn.c}: New files.
+
+ * hp300bsd-dep.c: Stay in sync with default-dep.c.
+
+ * m-hp300bsd.h (IN_SIGTRAMP): Define.
+
+Mon Nov 27 23:48:21 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * m-sparc.h (EXTRACT_RETURN_VALUE, STORE_RETURN_VALUE):
+ Return floating point values in %f0.
+
+Tue Nov 21 00:34:46 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * dbxread.c (read_type): #if 0 out code which skips to
+ comma following x-ref.
+
+Sat Nov 18 20:10:54 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * valprint.c (val_print): Undo changes of Nov 11 & 16.
+ (print_string): Add parameter force_ellipses.
+ (val_print): Pass force_ellipses true when we stop fetching string
+ before we get to the end, else pass false.
+
+Thu Nov 16 11:59:50 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * infrun.c (restore_inferior_status): Don't try to restore
+ selected frame if the inferior no longer exists.
+
+ * valprint.c (val_print): Rewrite string printing code not to
+ call print_string.
+
+ * Makefile.dist (clean): Remove xgdb and xgdb.o.
+
+Tue Nov 14 12:41:47 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * Makefile.dist (XGDB, bindir, xbindir, install, all): New stuff.
+
+Sat Nov 11 15:29:38 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * valprint.c (val_print): chars_to_get: New variable.
+
+Thu Nov 9 12:31:47 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * main.c (main): Process "-help" as a switch that doesn't
+ take an argument.
+
+Wed Nov 8 13:07:02 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * Makefile.dist (gdb.tar.Z): Add "else true".
+
+Tue Nov 7 12:25:14 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * infrun.c (restore_inferior_status): Don't dereference fid if NULL.
+
+ * config.gdb (sun3, sun4): Accept "sun3" and "sun4".
+
+Mon Nov 6 09:49:23 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * Makefile.dist (Makefile): Move comments after commands.
+
+ * *-dep.c [READ_COFF_SYMTAB]: Pass optional header size to
+ read_section_hdr().
+
+ * inflow.c: Include <fcntl.h> regardless of USG.
+
+ * coffread.c (read_section_hdr): Add optional_header_size.
+ (symbol_file_command): Pass optional header size to
+ read_section_hdr().
+ (read_coff_symtab): Initialize filestring.
+
+ * version.c: Change version to 3.4.xxx.
+
+ * GDB 3.4 released.
+
+Sun Nov 5 11:39:01 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * version.c: Change version to 3.4.
+
+ * symtab.c (decode_line_1): Only skip past "struct" if it
+ is there.
+
+ * valops.c (value_ind), eval.c (evaluate_subexp, case UNOP_IND):
+ Have "*" <int-valued-exp> return an int, not a LONGEST.
+
+ * utils.c (fprintf_filtered): Pass arg{4,5,6} to sprintf.
+
+ * printcmd.c (x_command): Use variable itself rather
+ than treating it as a pointer only if it is a function.
+ (See comment "this makes x/i main work").
+
+ * coffread.c (symbol_file_command): Use error for
+ "%s does not have a symbol-table.\n".
+
+Wed Nov 1 19:56:18 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * dbxread.c [BELIEVE_PCC_PROMOTION_TYPE]: New code.
+ m-sparc.h: Define BELIEVE_PCC_PROMOTION_TYPE.
+
+Thu Oct 26 12:45:00 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * infrun.c: Include <sys/dir.h>.
+
+ * dbxread.c (read_dbx_symtab, case N_LSYM, case 'T'):
+ Check for enum types and put constants in psymtab.
+
+Mon Oct 23 15:02:25 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * dbxread.c (define_symbol, read_dbx_symtab): Handle enum
+ constants (e.g. "b:c=e6,0").
+
+Thu Oct 19 14:57:26 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * stack.c (frame_info): Use FRAME_ARGS_ADDRESS_CORRECT
+ m-vax.h (FRAME_ARGS_ADDRESS_CORRECT): New macro.
+ (FRAME_ARGS_ADDRESS): Restore old meaning.
+
+ * frame.h (Frame_unknown): New macro.
+ stack.c (frame_info): Check for Frame_unknown return from
+ FRAME_ARGS_ADDRESS.
+ m-vax.h (FRAME_ARGS_ADDRESS): Sometimes return Frame_unknown.
+
+ * utils.c (fatal_dump_core): Add "internal error" to message.
+
+ * infrun.c (IN_SIGTRAMP): New macro.
+ (wait_for_inferior): Use IN_SIGTRAMP.
+ m-vax.h (IN_SIGTRAMP): New macro.
+
+Wed Oct 18 15:09:22 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * config.gdb, Makefile.dist: Shorten m-i386-sv32.h.
+
+ * coffread.c (symbol_file_command): Pass 0 to select_source_symtab.
+
+Tue Oct 17 12:24:41 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * i386-dep.c (i386_frame_num_args): Take function from m-i386.h
+ file. Check for pfi null.
+ m-i386.h (FRAME_NUM_ARGS): Use i386_frame_num_args.
+
+ * infrun.c (wait_for_inferior): set stop_func_name to 0
+ before calling find_pc_partial_function.
+
+Thu Oct 12 01:08:50 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * breakpoint.c (_initialize_breakpoint): Add "disa".
+
+ * Makefile.dist: Add GLOBAL_CFLAGS and pass to readline.
+
+ * config.gdb (various): "$machine =" -> "machine =".
+
+Wed Oct 11 11:54:31 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * inflow.c (try_writing_regs): #if 0 out this function.
+
+ * main.c (main): Add "-help" option.
+
+ * dbxread.c (read_dbx_symtab): Merge code for N_FUN with
+ N_STSYM, etc.
+
+Mon Oct 9 14:21:55 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * inflow.c (try_writing_regs_command): Don't write past end
+ of struct user.
+
+ * dbxread.c (read_struct_type): #if 0 out code which checks for
+ bitpos and bitsize 0.
+
+ * config.gdb: Accept sequent-i386 (not seq386).
+ (symmetry): Set depfile and paramfile.
+
+ * m-convex.h (IGNORE_SYMBOL): Check for N_MONPT if defined.
+
+Thu Oct 5 10:14:26 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * default-dep.c (read_inferior_memory): Put #if 0'd out comment
+ within /* */.
+
+Wed Oct 4 18:44:41 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * config.gdb: Change /dev/null to m-i386.h for various
+ 386 machine "opcodefile" entries.
+
+ * config.gdb: Accept seq386 for sequent symmetry.
+
+Mon Oct 2 09:59:50 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * hp300bsd-dep.c: Fix copyright notice.
+
+Sun Oct 1 16:25:30 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * Makefile.dist (DEPFILES): Add isi-dep.c.
+
+ * default-dep.c (read_inferior_memory): Move #endif after else.
+
+Sat Sep 30 12:50:16 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * version.c: Change version number to 3.3.xxx.
+
+ * GDB 3.3 released.
+
+ * version.c: Change version number to 3.3.
+
+ * Makefile.dist (READLINE): Add vi_mode.c
+
+ * config.gdb (i386): Change /dev/null to m-i386.h
+
+ * config.gdb: Add ';;' before 'esac'.
+
+ * Makefile.dist (gdb.tar.Z): Move comment above dependency.
+
+ * dbxread.c (read_ofile_symtab): Check symbol before start
+ of source file for GCC_COMPILED_FLAG_SYMBOL.
+ (start_symtab): Don't clear processing_gcc_compilation.
+
+Thu Sep 28 22:30:23 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * valprint.c (print_string): If LENGTH is zero, print "".
+
+Wed Sep 27 10:15:10 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * config.gdb: "rm tmp.c" -> "rm -f tmp.c".
+
+Tue Sep 26 13:02:10 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * utils.c (_initialize_utils): Use termcap to set lines_per_page
+ and chars_per_line.
+
+Mon Sep 25 10:06:43 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * dbxread.c (read_dbx_symtab, N_SOL): Do not add the same file
+ more than once.
+
+Thu Sep 21 12:43:18 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * infcmd.c (unset_environment_command): Delete all variables
+ if called with no arg.
+
+ * remote.c, inferior.h (remote_{read,write}_inferior_memory):
+ New functions.
+ core.c ({read,write}_memory): Use remote_{read,write}_inferior_memory.
+
+ * valops.c (call_function): When reserving stack space for
+ arguments, call value_arg_coerce.
+
+ * m-hp9k320.h: define BROKEN_LARGE_ALLOCA.
+
+ * breakpoint.c (delete_command): Ask for confirmation only
+ when there are breakpoints.
+
+ * dbxread.c (read_struct_type): If lookup_basetype_type has
+ copied a stub type, call add_undefined_type.
+
+ * sparc_pinsn.c (compare_opcodes): Check for "1+i" anywhere
+ in args.
+
+ * val_print.c (type_print_base): Print stub types as
+ "<incomplete type>".
+
+Wed Sep 20 07:32:00 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * sparc-opcode.h (swapa): Remove i bit from match.
+ (all alternate space instructions): Delete surplus "foo rs1+0"
+ patterns.
+
+ * Makefile.dist (LDFLAGS): Set to $(CFLAGS).
+
+ * remote-multi.shar (remote_utils.c, putpkt): Change csum to unsigned.
+
+Tue Sep 19 14:15:16 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * sparc-opcode.h: Set i bit in lose for many instructions which
+ aren't immediate.
+
+ * stack.c (print_frame_info): add "func = 0".
+
+Mon Sep 18 16:19:48 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * sparc-opcode.h (mov): Add mov to/from %tbr, %psr, %wim.
+
+ * sparc-opcode.h (rett): Fix notation to use suggested assembler
+ syntax from architecture manual.
+
+ * symmetry-dep.c (I386_REGNO_TO_SYMMETRY): New macro.
+ (i386_frame_find_saved_regs): Use I386_REGNO_TO_SYMMETRY.
+
+Sat Sep 16 22:21:17 1989 Jim Kingdon (kingdon at spiff)
+
+ * remote.c (remote_close): Set remote_desc to -1.
+
+ * gdb.texinfo (Output): Fix description of echo to match
+ reality and ANSI C.
+
+Fri Sep 15 14:28:59 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * symtab.c (lookup_symbol): Add comment about "asm".
+
+ * sparc-pinsn.c: Use NUMOPCODES.
+
+ * sparc-opcode.h (NUMOPCODES): Use sparc_opcodes[0] not *sparc_opcodes.
+
+Thu Sep 14 15:25:20 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (xxmalloc): Print error message before calling abort().
+
+ * infrun.c (wait_for_inferior): Check for {stop,prev}_func_name
+ null before passing to strcmp.
+
+Wed Sep 13 12:34:15 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * sparc-opcode.h: New field delayed.
+ sparc-pinsn.c (is_delayed_branch): New function.
+ (print_insn): Check for delayed branches.
+
+ * stack.c (print_frame_info): Use misc_function_vector in
+ case where ar truncates file names.
+
+Tue Sep 12 00:16:14 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * convex-dep.c (psw_info): Move "struct pswbit *p" with declarations.
+
+Mon Sep 11 14:59:57 1989 Jim Kingdon (kingdon at spiff)
+
+ * convex-dep.c (core_file_command): Delete redundant printing
+ of "Program %s".
+
+ * m-convex.h (ENTRY_POINT): New macro.
+
+ * m-convex.h (FRAME_CHAIN_VALID): Change outside_first_object_file
+ to outside_startup_file
+
+ * main.c: #if 0 out catch_termination and related code.
+
+ * command.c (lookup_cmd_1): Consider underscores part of
+ command names.
+
+Sun Sep 10 09:20:12 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * printcmd.c: Change asdump_command to disassemble_command
+ (_initialize_printcmd): Change asdump to diassemble.
+
+ * main.c (main): Exit with code 0 if we hit the end of a batch
+ file.
+
+ * Makefile.dist (libreadline.a): Fix syntax of "CC=${CC}".
+
+Sat Sep 9 01:07:18 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * values.c (history_info): Renamed to value_history_info.
+ Command renamed to "info value" (with "info history" still
+ accepted).
+
+ * sparc-pinsn.c (print_insn): Extend symbolic address printing
+ to cover "sethi" following by an insn which uses 1+i.
+
+Fri Sep 8 14:24:01 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * m-hp9k320.h, m-hp300bsd.h, m-altos.h, m-sparc.h, m-sun3.h
+ (READ_GDB_SYMSEGS): Remove.
+ dbxread.c [READ_GDB_SYMSEGS]: Remove code to read symsegs.
+
+ * sparc-pinsn.c (print_insn): Detect "sethi-or" pairs and
+ print symbolic address.
+
+ * sparc-opcode.h (sethi, set): Change lose from 0xc0000000 to
+ 0xc0c00000000.
+
+ * remote.c (remote_desc): Initialize to -1.
+
+ * Makefile.dist (libreadline.a): Pass CC='${CC}' to readline makefile.
+
+Thu Sep 7 00:07:17 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (read_struct_type): Check for static member functions.
+ values.c, eval.c, valarith.c, valprint.c, valops.c: Merge changes
+ from Tiemann for static member functions.
+
+ * sparc-opcode.h (tst): Fix all 3 patterns.
+
+ * Makefile.dist (gdb1): New rule.
+
+ * sparc-opcode.h: Change comment about what the disassembler
+ does with the order of the opcodes.
+
+ * sparc-pinsn.c (compare_opcodes): Put 1+i before i+1.
+ Also fix mistaken comment about preserving order of original table.
+
+ * sparc-opcode.h (clr, mov): Fix incorrect lose entries.
+
+ * m-symmetry.h (FRAME_NUM_ARGS): Add check to deal with code that
+ GCC sometimes generates.
+
+ * config.gdb: Change all occurances of "skip" to "/dev/null".
+
+ * README (about languages other than C): Update comments about
+ Pascal and FORTRAN.
+
+ * sparc-opcode.h (nop): Change lose from 0xae3fffff to 0xfe3fffff.
+
+ * values.c (value_virtual_fn_field): #if 0-out assignment to
+ VALUE_TYPE(vtbl).
+
+Wed Sep 6 12:19:22 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * utils.c (fatal_dump_core): New function.
+ Makefile.dist (MALLOC_FLAGS): use -Dbotch=fatal_dump_core
+
+Tue Sep 5 15:47:18 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * breakpoint.c (enable_command): With no arg, enable all bkpts.
+
+ * Makefile.dist (Makefile): Remove \"'s around $(MD).
+
+ * Makefile.dist: In "cd readline; make . . ." change first
+ SYSV_DEFINE to SYSV.
+
+ * m68k-pinsn.c (_initialize_pinsn): Use alternate assembler
+ syntax #ifdef HPUX_ASM
+
+Sat Sep 2 23:24:43 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * values.c (history_info): Don't check num_exp[0] if num_exp
+ is nil (just like recent editing_info change).
+
+Fri Sep 1 19:19:01 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * gdb.texinfo (inc-history, inc-readline): Copy in the inc-* files
+ because people might not have makeinfo.
+
+ * README (xgdb): Strengthen nasty comments.
+
+ * gdb.texinfo: Change @setfilename to "gdb.info".
+
+Thu Aug 31 17:23:50 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * main.c (editing_info): Don't check arg[0] if arg is null.
+
+ * m-vax.h: Add comment about known sigtramp bug.
+
+ * sun3-dep.c, sparc-dep.c (IS_OBJECT_FILE, exec_file_command):
+ Get right text & data addresses for .o files.
+
+Wed Aug 30 13:54:19 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * utils.c (tilde_expand): Remove function (it's in readline).
+
+ * sparc-opcode.h (call): Change "8" to "9" in first two
+ patterns (%g7->%o7).
+
+Tue Aug 29 16:44:41 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * printcmd.c (whatis_command): Change 4th arg to type_print
+ from 1 to -1.
+
+Mon Aug 28 12:22:41 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * dbxread.c (psymtab_to_symtab_1): In "and %s ..." change
+ pst->filename to pst->dependencies[i]->filename.
+
+ * blockframe.c (FRAMELESS_LOOK_FOR_PROLOGUE): New macro
+ made from FRAMELESS_FUNCTION_INVOCATION from m-sun3.h except
+ that it checks for zero return from get_pc_function_start.
+ m-hp9k320.h, m-hp300bsd.h, m-i386.h, m-isi.h, m-altos.h,
+ m-news.h, m-sparc.h, m-sun2.h, m-sun3.h, m-symmetry.h
+ (FRAMELESS_FUNCTION_INVOCATION): Use FRAMELESS_LOOK_FOR_PROLOGUE.
+
+ * dbxread.c (read_struct_type): Give warning and ignore field
+ if bitpos and bitsize are zero.
+
+Sun Aug 27 04:55:20 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (psymtab_to_symtab{,_1}): Print message about
+ reading in symbols before reading stringtab, not after.
+
+Sat Aug 26 02:01:53 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * dbxread.c (IS_OBJECT_FILE, ADDR_OF_TEXT_SEGMENT): New macros.
+ (read_dbx_symtab): Use text_addr & text_size to set end_of_text_addr.
+ (symbol_file_command): pass text_addr & text_size to read_dbx_symtab.
+
+Fri Aug 25 23:08:13 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * valprint.c (value_print): Try to give the name of function
+ pointed to when printing a function pointer.
+
+Thu Aug 24 23:18:40 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * core.c (xfer_core_file): In cases where MEMADDR is above the
+ largest address that makes sense, set i to len.
+
+Thu Aug 24 16:04:17 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * valprint.c (print_string): New function to print a character
+ string, doing array-max limiting and repeat count processing.
+ (val_print, value_print): Use print_string.
+ (REPEAT_COUNT_THRESHOLD): New #define, the max number of elts to print
+ without using a repeat count. Set to ten.
+ (value_print, val_print): Use REPEAT_COUNT_THRESHOLD.
+
+ * utils.c (printchar): Use {fputs,fprintf}_filtered.
+
+ * valprint.c (val_print): Pass the repeat count arg to the
+ fprintf_filtered call for "<repeats N times>" messages.
+
+Wed Aug 23 22:53:47 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * utils.c: Include <pwd.h>.
+
+ * main.c: Declare free.
+
+Wed Aug 23 05:05:59 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * utils.c, defs.h: Add tilde_expand.
+ source.c (directory_command),
+ main.c (cd_command),
+ main.c (set_history_filename),
+ dbxread.c (symbol_file_command),
+ coffread.c (symbol_file_command),
+ dbxread.c (add_file_command),
+ symmisc.c (print_symtabs),
+ *-dep.c (exec_file_command, core_file_command),
+ main.c (source_command): Use tilde_expand.
+
+ * dbxread.c (read_type): When we get a cross-reference, resolve
+ it immediately if possible, only calling add_undefined_type if
+ necessary.
+
+ * gdb.texinfo: Uncomment @includes and put comment at start
+ of file telling people to use makeinfo.
+
+ * valprint.c (type_print_base): Print the right thing for
+ bitfields.
+
+ * config.gdb (sun3os3): Set paramfile and depfile.
+
+Tue Aug 22 05:38:36 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * dbxread.c (symbol_file_command): Pass string table size to
+ read_dbx_symtab().
+ (read_dbx_symtab): Before indexing into string table, check
+ string table index for reasonableness.
+ (psymtab_to_symtab{,_1}, read_ofile_symtab): Same.
+
+Tue Aug 22 04:04:39 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * m68k-pinsn.c: Replaced many calls to fprintf and fputs with
+ calls to fprintf_filtered and fputs_filtered.
+ (print_insn_arg): Use normal MIT 68k syntax for postincrement,
+ predecrement, and register indirect addressing modes.
+
+Mon Aug 21 10:08:02 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * main.c (initialize_signals): Set signal handler for SIGQUIT
+ and SIGHUP to do_nothing.
+
+ * ns32k-opcode.h (ord): Change 1D1D to 1D2D.
+
+ * ns32k-pinsn.c (print_insn_arg, print_insn): Handle index
+ bytes correctly.
+
+ * ns32k-opcode.h: Add comments.
+
+ * dbxread.c (read_type): Put enum fields in type.fields in order
+ that they were found in the debugging symbols (not reverse order).
+
+Sun Aug 20 21:17:13 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * main.c (source_command): Read .gdbinit if run without argument.
+
+ * source.c (directory_command): Only print "foo already in path"
+ if from_tty.
+
+ * version.c: Change version number to 3.2.xxx
+
+Sat Aug 19 00:24:08 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * m-news.h: Define HAVE_WAIT_STRUCT.
+
+ * m-isi.h, isi-dep.c: Replace with new version from Adam de Boor.
+ config.gdb: Remove isibsd43.
+
+ * main.c (catch_termination): Don't say we have written
+ .gdb_history until after we really have.
+
+ * convex-dep.c (attach): Add "sleep (1)".
+ (write_vector_register): Use "LL" with long long constant.
+ (wait): Close comment.
+ (wait): Change "unix 7.1 bug" to "unix 7.1 feature" & related
+ changes in comment.
+ (scan_stack): And fp with 0x80000000 in while loop test.
+ (core_file_command): Move code to set COREFILE.
+ (many places): Change printf to printf_filtered.
+ (psw_info): Allow argument giving value to print as a psw.
+ (_initialize_convex_dep): Update docstrings.
+
+ * m-convex.h (WORDS_BIG_ENDIAN): Correct typo ("WRODS")
+ define NO_SIGINTERRUPT.
+ define SET_STACK_LIMIT_HUGE.
+ add "undef BUILTIN_TYPE_LONGEST" before defining it.
+ Use "LL" after constants in CALL_DUMMY.
+
+ * dbxread.c: In the 3 places it says error "ridiculous string
+ table size"... delete extra parameter to error.
+
+ * dbxread.c (scan_file_globals): Check for FORTRAN common block.
+ Allow multiple references for the sake of common blocks.
+
+ * main.c (initialize_main): Set history_filename to include
+ current directory.
+
+ * valprint.c (decode_format): Don't return a defaulted size
+ field if osize is zero.
+
+ * gdb.texinfo (Compilation): Update information on -gg symbols.
+ Document problem with ar.
+
+Fri Aug 18 19:45:20 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * valprint.c (val_print, value_print): Add "<repeats %d times>" code.
+ Also put "..." outside quotes for strings.
+
+ * main.c (initialize_main): Add comment about history output file
+ being different from history input file.
+
+ * m-newsos3.h: Undefine NO_SIGINTERRUPT. Rearrange a few comments.
+
+ * m-newsos3.h (REGISTER_U_ADDR): Use new version from Hikichi.
+
+ * sparc-opcode.h: Add comment clarifying meaning of the order of
+ the entries in sparc_opcodes.
+
+ * eval.c (evaluate_subexp, case UNOP_IND): Deal with deferencing
+ things that are not pointers.
+
+ * valops.c (value_ind): Make dereferencing an int give a LONGEST.
+
+ * expprint.c (print_subexp): Add (int) cast in OP_LAST case.
+
+ * dbxread.c (read_array_type): Set lower and upper if adjustable.
+
+ * symtab.c (lookup_symbol): Don't abort if symbol found in psymtab
+ but not in symtab.
+
+Thu Aug 17 15:51:20 1989 Randy Smith (randy at hobbes.ai.mit.edu)
+
+ * config.gdb: Changed "Makefile.c" to "Makefile.dist".
+
+Thu Aug 17 01:58:04 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu)
+
+ * sparc-opcode.h (or): Removed incorrect lose bit 0x08000000.
+ [many]: Changed many `lose' entries to have the 0x10 bit set, so
+ they don't think %l0 is %g0.
+
+Wed Aug 16 00:30:44 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * m-symmetry.h (STORE_STRUCT_RETURN): Also write reg 0.
+ (EXTRACT_RETURN_VALUE): Call symmetry_extract_return_value.
+ symmetry-dep.c (symmetry_extract_return_value): New fn.
+
+ * main.c (symbol_completion_function): Deal with changed
+ result_list from lookup_cmd_1 for ambiguous return.
+ command.c (lookup_cmd): Same.
+
+ * inflow.c [TIOCGETC]: Move #include "param.h" back before
+ system #includes. Change all #ifdef TIOCGETC to
+ #if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+ m-i386-sysv3.2.h, m-i386gas-sysv3.2.h: Remove "#undef TIOCGETC"
+ and add "#define TIOCGETC_BROKEN".
+
+ * command.c (lookup_cmd_1): Give the correct result_list in the
+ case of an ambiguous return where there is a partial match
+ (e.g. "info a"). Add comment clarifying what is the correct
+ result_list.
+
+ * gdb.texinfo (GDB History): Document the two changes below.
+
+ * main.c (command_line_input): Make history expansion not
+ just occur at the beginning of a line.
+
+ * main.c (initialize_main): Make history expansion off by default.
+
+ * inflow.c: Move #include "param.h" after system #includes.
+
+ * i386-dep.c (i386_float_info): Use U_FPSTATE macro.
+
+ * m-i386-sysv3.2.h, m-i386gas-sysv3.2.h: New files.
+ Makefile.dist, config.gdb: Know about these new files.
+
+Tue Aug 15 21:36:11 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * symtab.c (lookup_struct_elt_type): Use type_print rather
+ than assuming type has a name.
+
+Tue Aug 15 02:25:43 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu)
+
+ * sparc-opcode.h (mov): Removed bogus "or i,0,d" pattern.
+
+ * sparc-opcode.h (mov, or): Fixed incorrect `lose' members.
+
+ * sparc-dep.c: Don't include "sparc-opcode.h".
+ (skip_prologue, isanulled): Declare special types to recognize
+ instructions, and use them.
+
+ * sparc-pinsn.c (print_insn): Sign-extend 13-bit immediate args.
+ If they are less than +9, print them in signed decimal instead
+ of unsigned hex.
+
+ * sparc-opcode.h, sparc-pinsn.c: Completely rewritten to share an
+ opcode table with gas, and thus produce disassembly that looks
+ like what the assembler accepts.
+
+Tue Aug 15 16:20:52 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * symtab.c (find_pc_psymbol): Move best_pc=psymtab->textlow-1
+ after test for psymtab null.
+
+ * main.c (editing_info): Remove variable retval.
+
+ * config.gdb (sun3, isi): Comment out obsolete message about telling
+ it whether you have an FPU (now that it detects it).
+
+ * config.gdb (sun3): Accept sun3os3.
+
+ * m68k-insn.h: Include <signal.h>.
+
+ * m68k-pinsn.h (convert_{to,from}_68881): Add have_fpu code
+
+ * m-newsos3.h: Undefine USE_PCB. That code didn't seem to work.
+
+ * sparc-dep.c: Put in insn_fmt and other stuff from the old
+ sparc-opcode.h.
+
+ * sparc-opcode.h, sparc-pinsn.c: Correct copyright notice.
+
+ * sparc-opcode.h, sparc-pinsn.c: Replace the old ones with the new
+ ones by roland.
+
+Tue Aug 15 02:25:43 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu)
+
+ * Makefile.dist: Don't define CC at all.
+
+ * Makefile.dist (Makefile): Remove tmp.c after preprocessing.
+ Use $(MD) instead of M_MAKEDEFINE in the cc command.
+
+ * Makefile.dist: Don't define RL_LIB as
+ "${READLINE}/libreadline.a", since READLINE is a list of files.
+
+Mon Aug 14 23:49:29 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * main.c (print_version): Change 1988 to 1989.
+
+ * main.c (copying_info, initialize_main): Remove #if 0'd code.
+
+Tue Aug 1 14:44:56 1989 Hikichi (hikichi at sran203)
+
+ * m-newsos3.h
+ (NO_SIGINTERRUPT): have SIGINTERRUPT on NEWS os 3.
+
+ * m-news.h(FRAME_FIND_SAVED_REGS): use the sun3's instead of old
+ one.
+
+Mon Aug 14 15:27:01 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * m-news.h, m-newsos3.h, news-dep.c: Merge additional changes
+ by Hikichi (ChangeLog entries above).
+
+ * Makefile.dist (READLINE): List readline files individually
+ so we don't accidently get random files from the readline
+ directory.
+
+ * m-news.h (STORE_RETURN_VALUE, EXTRACT_RETURN_VALUE):
+ Expect floating point returns to be in fp0.
+
+ * gdb.texinfo (Format options): New node.
+
+ * gdb.texinfo: Comment out "@include"s until bfox fixes the
+ readline & history docs.
+
+ * dbxread.c (read_addl_syms): Set startup_file_* if necessary at
+ the end (as well as when we hit ".o").
+
+ * printcmd.c (decode_format): Set val.format & val.size to '?' at
+ start and set defaults at end.
+
+ * symtab.c (decode_line_1): Check for class_name null.
+
+ * valops.c: Each place where it compares against field names,
+ check for null field names. (new t_field_name variables).
+
+ * utils.c (fputs_filtered): Check for linebuffer null before
+ checking whether to call fputs. Remove later check for linebuffer
+ null.
+
+Sun Aug 13 15:56:50 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * m-isi.h, m-sun3.h ({PUSH,POP}_FP_REGS): New macros.
+ m-sun3.h (NUM_REGS): Conditionalize on FPU.
+ config.gdb (sun3, isi): Add message about support for machines
+ without FPU.
+
+ * main.c (catch_termination, initialize_signals): new functions.
+
+ * main.c (editing_info): Add "info editing n" and "info editing +".
+ Rewrite much of this function.
+ gdb.texinfo (GDB Readline): Document it.
+
+ * values.c (history_info): Add "info history +". Also add code to
+ do "info history +" when command is repeated.
+ gdb.texinfo (Value History): Document "info history +".
+
+ * expprint.c (print_subexp): Add OP_THIS to case stmt.
+
+ * config.gdb (sun4os4): Put quotes around make define.
+
+ * config.gdb: Canonicalize machine name at beginning.
+
+Sat Aug 12 00:50:59 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * config.gdb: define M_MAKEDEFINE
+ Makefile (Makefile, MD): Be able to re-make Makefile.
+
+ * main.c (command_line_input): Add comments to
+ the command history.
+
+ * Makefile.dist (Makefile): Add /bin/false.
+
+Fri Aug 11 14:35:33 1989 Jim Kingdon (kingdon at spiff)
+
+ * Makefile.dist: Comment out .c.o rule and add TARGET_ARCH.
+
+ * m-altos.h: Include sys/page.h & sys/net.h
+
+ * m-altos.h (FRAME_CHAIN{,_VALID}): Use outside_startup_file.
+
+ * config.gdb (altos, altosgas): Add M_SYSV & M_BSD_NM and remove
+ M_ALLOCA=alloca.o from makedefine.
+
+ * coffread.c (complete_symtab): Change a_entry to entry.
+
+ * m-altosgas.h: New file.
+
+ * m-symmetry (REGISTER_BYTE): Fix dumb mistake.
+
+Fri Aug 11 06:39:49 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * utils.c (set_screensize_command): Check for ARG being nil, since
+ that's what execute_command will pass if there's no argument.
+
+ * expread.y (yylex): Recognize "0x" or "0X" as the beginning of a
+ number.
+
+Thu Aug 10 15:43:12 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * config.gdb, Makefile.dist: Rename Makefile.c to Makefile.dist.
+
+ * m-altos.h: Add comment about porting to USGR2.
+
+ * config.gdb (sparc): Add -Usparc.
+
+Wed Aug 9 14:20:39 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * m-sun3os4.h: Define BROKEN_LARGE_ALLOCA.
+
+ * values.c (modify_field): Check for value too large to fit in
+ bitfield.
+
+ * utils.c (fputs_filtered): Allow LINEBUFFER to be NULL.
+
+ * breakpoint.c (condition_command): Check for attempt to specify
+ non-numeric breakpoint number.
+
+ * config.gdb, Makefile, m-altos.h, altos-dep.c: Merge Altos
+ port.
+
+ * README: Change message about editing Makefile.
+
+ * config.gdb: Edit Makefile.
+ Copied Makefile to Makefile.c and changed to let config.gdb
+ run us through the C preprocessor.
+
+ * expread.y (yylex): Test correctly for definition of number.
+
+Wed Aug 9 11:56:05 1989 Randy Smith (randy at hobbes.ai.mit.edu)
+
+ * dbxread.c (read_dbx_symtab): Put bracketing of entry point in
+ test case for .o symbols so that it will be correct even without
+ debugging symbols.
+ (end_psymtab): Took bracketing out.
+
+ * blockframe.c (outside_startup_file): Reverse the sense of the
+ return value to make the functionality implied by the name
+ correct.
+
+Tue Aug 8 11:48:38 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * coffread.c (symbol_file_command): Do not assume presence of a.out
+ header.
+
+ * blockframe.c: Replace first_object_file_end with
+ startup_file_{start,end}
+ (outside_startup_file): New function.
+ dbxread.c (read_addl_syms, read_dbx_symtab, end_psymbol): set
+ startup_file_*. Delete first_object_file_end code.
+ Add entry_point and ENTRY_POINT
+ coffread.c (complete_symtab): Set startup_file_*.
+ (first_object_file_end): Add as static.
+ m-*.h (FRAME_CHAIN, FRAME_CHAIN_VALID): Call outside_startup_file
+ instead of comparing with first_object_file_end.
+
+ * breakpoint.c (breakpoint_1): Change -1 to (CORE_ADDR)-1.
+
+ * config.gdb (i386, i386gas): Add missing quotes at end of "echo"
+
+ * source.c (directory_command): Add dont_repeat ();
+
+Mon Aug 7 18:03:51 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * dbxread.c (read_addl_syms): Change strcmp to strncmp and put 3rd
+ arg back.
+
+ * command.h (struct cmd_list_element): Add comment clarifying
+ purpose of abbrev_flag.
+
+Mon Aug 7 12:51:03 1989 Randy Smith (randy at hobbes.ai.mit.edu)
+
+ * printcmd.c (_initialize_printcmd): Changed "undisplay" not to
+ have abbrev flag set; it isn't an abbreviation of "delete
+ display", it's an alias.
+
+Mon Aug 7 00:25:15 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * symtab.c (lookup_symtab_1): Remove filematch (never used).
+
+ * expread.y [type]: Add second argument to 2 calls to
+ lookup_member_type which were missing them.
+
+ * dbxread.c (symbol_file_command): Add from_tty arg.
+ Check it before calling query.
+
+ * infcmd.c (tty_command): Add from_tty arg.
+
+ * eval.c (evaluate_subexp): Remove 3rd argument from
+ calls to value_x_unop.
+
+ * dbxread.c (read_addl_syms): Remove 3rd argument from
+ call to strcmp.
+
+ * gdb.texinfo (Command editing): @include inc-readline.texinfo
+ and inc-history.texinfo and reorganize GDB-specific stuff.
+
+ * Makefile: Add line MAKE=make.
+
+ * README (second paragraph): Fix trivial errors.
+
+ * dbxread.c (read_struct_type): Make sure p is initialized.
+
+ * main.c (symbol_completion_function): Complete correctly
+ on the empty string.
+
+Sun Aug 6 21:01:59 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * symmetry-dep.c: Remove "long" from definition of i386_follow_jump.
+
+ * gdb.texinfo (Backtrace): Document "where" and "info stack".
+
+ * dbxread.c (cleanup_undefined_types): Strip off "struct "
+ or "union " from type names before doing comparison
+
+Sat Aug 5 02:05:36 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * config.gdb (i386, i386gas): Improve makefile editing instructions.
+
+ * Makefile: Fix typo in CLIBS for SYSV.
+
+ * dbxread.c (read_dbx_symtab): Deal with N_GSYM typedefs.
+
+ * dbxread.c (add_file_command): Do not free name. We didn't
+ allocate it; it just points into arg_string.
+
+ * Makefile, m-*.h: Change LACK_VPRINTF to HAVE_VPRINTF.
+
+Fri Jul 28 00:07:48 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * valprint.c (val_print): Made sure that all returns returned a
+ value (usually 0, indicating no memory printed).
+
+ * core.c (read_memory): Changed "return" to "return 0".
+
+ * expread.y (parse_number): Handle scientific notation when the
+ string does not contain a '.'.
+
+Thu Jul 27 15:14:03 1989 Randy Smith (randy at hobbes.ai.mit.edu)
+
+ * infrun.c (signals_info): Error if signal number passed is out of
+ bounds.
+
+ * defs.h: Define alloca to be __builtin_alloca if compiling with
+ gcc and localized inclusion of alloca.h on the sparc with the
+ other alloca stuff.
+ * command.c: Doesn't need to include alloca.h on the sparc; defs.h
+ does it for you.
+
+ * printcmd.c (print_frame_args): Changed test for call to
+ print_frame_nameless_args to check i to tell if any args had been
+ printed.
+
+Thu Jul 27 04:40:56 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * blockframe.c (find_pc_partial_function): Always check that NAME
+ and/or ADDRESS are not nil before storing into them.
+
+Wed Jul 26 23:41:21 1989 Roland McGrath (roland at hobbes.ai.mit.edu)
+
+ * m-newsos3.h: Define BROKEN_LARGE_ALLOCA.
+ * dbxread.c (symbol_file_command, psymtab_to_symtab):
+ Use xmalloc #ifdef BROKEN_LARGE_ALLOCA.
+
+Tue Jul 25 16:28:18 1989 Jay Fenlason (hack at apple-gunkies.ai.mit.edu)
+
+ * m68k-opcode.h: moved some of the fmovem entries so they're
+ all consecutive. This way the assembler doesn't bomb.
+
+Mon Jul 24 22:45:54 1989 Randy Smith (randy at hobbes.ai.mit.edu)
+
+ * symtab.c (lookup_symbol): Changed error to an informational (if
+ not very comforting) message about internal problems. This will
+ get a null symbol returned to decode_line_1, which should force
+ things to be looked up in the misc function vector.
+
+Wed Jul 19 13:47:34 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * symtab.c (lookup_symbol): Changed "fatal" to "error" in
+ external symbol not found in symtab in which it was supposed to be
+ found. This can be reached because of a bug in ar.
+
+Tue Jul 18 22:57:43 1989 Randy Smith (roland at hobbes.ai.mit.edu)
+
+ * m-news.h [REGISTER_U_ADDR]: Decreased the assumed offset of fp0
+ by 4 to bring it into (apparently) appropriate alignment with
+ reality.
+
+Tue Jul 18 18:14:42 1989 Randy Smith (randy at hobbes.ai.mit.edu)
+
+ * Makefile: pinsn.o should depend on opcode.h
+
+ * m68k-opcode.h: Moved fmovemx with register lists to before other
+ fmovemx.
+
+Tue Jul 18 11:21:42 1989 Jim Kingdon (kingdon at susie)
+
+ * Makefile, m*.h: Only #define vprintf (to _doprnt or printf,
+ depends on the system) if the library lacks it (controlled by
+ LACK_VPRINTF_DEFINE in makefile). Unpleasant, but necessary to
+ make this work with the GNU C library.
+
+Mon Jul 17 15:17:48 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * breakpoint.c (breakpoint_1): Change addr-b->address to
+ b->address-addr.
+
+Sun Jul 16 16:23:39 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * eval.c (evaluate_subexp): Change error message printed when
+ right operand of '@' is not an integer to English.
+
+ * infcmd.c (registers_info): Fix call to print_spaces_filtered
+ to specify right # of arguments.
+
+ * gdb.texinfo (Command Editing): Document info editing command.
+
+ * coffread.c (read_file_hdr): Add MC68MAGIC.
+
+ * source.c (select_source_symtab): Change MAX to max.
+
+Fri Jul 14 21:19:11 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * infcmd.c (registers_info): Clean up display to look good with long
+ register names, to say "register" instead of "reg", and to put the
+ "relative to selected stack frame" bit at the top.
+
+Fri Jul 14 18:23:09 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (record_misc_function): Put parens around | to force
+ correct evaluation.
+
+Wed Jul 12 12:25:53 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * m-newsos3, m-news, infrun.c, Makefile, config.gdb, news-dep.c:
+ Merge in Hikichi's changes for Sony/News-OS 3 support.
+
+Tue Jul 11 21:41:32 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * utils.c (fputs_filtered): Don't do any filtering if output is
+ not to stdout, or if stdout is not a tty.
+ (fprintf_filtered): Rely on fputs_filtered's check for whether to
+ do filtering.
+
+Tue Jul 11 00:33:58 1989 Randy Smith (randy at hobbes.ai.mit.edu)
+
+ * GDB 3.2 Released.
+
+ * valprint.h: Deleted.
+
+ * utils.c (fputs_filtered): Don't do any filtering if filtering is
+ disabled (lines_per_page == 0).
+
+Mon Jul 10 22:27:53 1989 Randy Smith (roland at hobbes.ai.mit.edu)
+
+ * expread.y [typebase]: Added "unsigned long int" and "unsigned
+ short int" to specs.
+
+Mon Jul 10 21:44:55 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * main.c (main): Make -cd use cd_command to avoid
+ current_directory with non-absolute pathname.
+
+Mon Jul 10 00:34:29 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (symbol_file_command): Catch errors from stat (even
+ though they should never happen).
+
+ * source.c (openp): If the path is null, use the current
+ directory.
+
+ * dbxread.c (read_dbx_symtab): Put N_SETV symbols into the misc
+ function vector ...
+ (record_misc_function): ... as data symbols.
+
+ * utils.c (fprintf_filtered): Return after printing if we aren't
+ going to do filtering.
+
+ * Makefile: Added several things for make clean to take care of.
+
+ * expread.y: Lowered "@" in precedence below +,-,*,/,%.
+
+ * eval.c (evaluate_subexp): Return an error if the rhs of "@"
+ isn't integral.
+
+ * Makefile: Added removal of core and gdb[0-9] files to clean
+ target.
+
+ * Makefile: Made a new target "distclean", which cleans things up
+ correctly for making a distribution.
+
+Sun Jul 9 23:21:27 1989 Randy Smith (randy at hobbes.ai.mit.edu)
+
+ * dbxread.c: Surrounded define of gnu symbols with an #ifndef
+ NO_GNU_STABS in case you don't want them on some machines.
+ * m-npl.h, m-pn.h: Defined NO_GNU_STABS.
+
+Sun Jul 9 19:25:22 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * utils.c (fputs_filtered): New function.
+ (fprintf_filtered): Use fputs_filtered.
+ utils.c (print_spaces_filtered),
+ command.c (help_cmd,help_cmd_list),
+ printcmd.c (print_frame_args),
+ stack.c (print_block_frame_locals, print_frame_arg_vars),
+ valprint.c (many functions): Use fputs_filtered instead of
+ fprintf_filtered to avoid arbitrary limit.
+
+ * utils.c (fprintf_filtered): Fix incorrect comment.
+
+Sat Jul 8 18:12:01 1989 Randy Smith (randy at hobbes.ai.mit.edu)
+
+ * valprint.c (val_print): Changed assignment of pretty to use
+ prettyprint as a conditional rather than rely on values of the
+ enum.
+
+ * Projects: Cleaned up a little for release.
+
+ * main.c (initialize_main): Initialize
+ rl_completion_entry_function instead of completion_entry_function.
+
+ * Makefile: Modified to use the new readline library setup.
+
+ * breakpoint.c (break_command_1, delete_breakpoint,
+ enable_breakpoint, disable_breakpoint): Put in new printouts for
+ xgdb usage triggered off of xgdb_verbose.
+ * main.c (main): Added check for flag to set xgdb_verbose.
+ * stack.c (frame_command): Set frame_changed when frame command
+ used.
+
+Fri Jul 7 16:20:58 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * Remove valprint.h and move contents to value.h (more logical).
+
+Fri Jul 7 02:28:06 1989 Randall Smith (randy at rice-chex)
+
+ * m68k-pinsn.c (print_insn): Included a check for register list;
+ if there is one, make sure to start p after it.
+
+ * breakpoint.c (break_command_1, delete_breakpoint,
+ enable_breakpoint, disable_breakpoint): #ifdef'd out changes
+ below; they produce unwanted output in gdb mode in gnu-emacs.
+
+ * gdb.texinfo: Spelled. Also removed index references from
+ command editing section; the relevance/volume ratio was too low.
+ Removed all references to the function index.
+
+ * ns32k-opcode.h, ns32k-pinsn.c: Backed out changes of June 24th;
+ haven't yet received legal papers.
+
+ * .gdbinit: Included message telling the user what it is doing.
+
+ * symmetry-dep.c: Added static decls for i386_get_frame_setup,
+ i386_follow_jump.
+ * values.c (unpack_double): Added a return (double)0 at the end to
+ silence a compiler warning.
+
+ * printcmd.c (containing_function_bounds, asdump_command): Created
+ to dump the assembly code of a function (support for xgdb and a
+ useful hack).
+ (_initialize_printcmd): Added this to command list.
+ * gdb.texinfo [Memory]: Added documentation for the asdump
+ command.
+ * breakpoint.c (break_command_1, delete_breakpoint,
+ enable_breakpoint, disable_breakpoint): Added extra verbosity for
+ xgdb conditionalized on the new external frame_full_file_name.
+ * source.c (identify_source_line): Increase verbosity of fullname
+ prointout to include pc value.
+ * stack.c: Added a new variable; "frame_changed" to indicate when
+ a frame has been changed so that gdb can print out a frame change
+ message when the frame only changes implicitly.
+ (print_frame_info): Check the new variable in determining when to
+ print out a new message and set it to zero when done.
+ (up_command): Increment it.
+ (down_command): Decrement it.
+
+ * m68k-pinsn.c (print_insn_arg [lL]): Modified cases for register
+ lists to reset the point to point to after the word from which the
+ list is grabbed *if* that would cause point to point farther than
+ it currently is.
+
+Thu Jul 6 14:28:11 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * valprint.c (val_print, value_print): Add parameter to control
+ prettyprinting.
+ valprint.h: New file containing constants used for passing
+ prettyprinting parameter to val{,ue}_print.
+ expprint.c, infcmd.c, printcmd.c, valprint.c, values.c:
+ Change all calls to val{,ue}_print to use new parameter.
+
+Mon Jul 3 22:38:11 1989 Randy Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (,process_one_symbol): Moved extern declaration for
+ index out of function to beginning of file.
+
+Mon Jul 3 18:40:14 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * gdb.texinfo (Registers): Add "ps" to list of standard registers.
+
+Sun Jul 2 23:13:03 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * printcmd.c (enable_display): Change d->next to d = d->next so
+ that "enable display" without args works.
+
+Fri Jun 30 23:42:04 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * source.c (list_command): Made error message given when no
+ symtab is loaded clearer.
+
+ * valops.c (value_assign): Make it so that when assigning to an
+ internal variable, the type of the assignment exp is the type of
+ the value being assigned.
+
+Fri Jun 30 12:12:43 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * main.c (verbose_info): Created.
+ (initialize_main): Put "info verbose" into command list.
+
+ * utils.c (screensize_info): Created.
+ (_initialize_utils): Defined "info screensize" as a normal command.
+
+ * valprint.c (format_info): Added information about maximum number
+ of array elements to function.
+
+ * blockframe.c (find_pc_partial_function): Again.
+
+ * blockframe.c (find_pc_partial_function): Replaced a "shouldn't
+ happen" (which does) with a zero return.
+
+ * main.c (dont_repeat): Moved ahead of first use.
+
+Thu Jun 29 19:15:08 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * vax-opcode.h: Made minor modifications (moved an instruction and
+ removed a typo) to bring this into accord with gas' table; also
+ changed copyright to reflect it being part of both gdb and gas.
+
+ * m68k-opcode.h: Added whole scads and bunches of new stuff for
+ the m68851 and changed the coptyrightto recognize that the file
+ was shared between gdb and gas.
+
+ * main.c (stop_sig): Use "dont_repeat ()" instead of *line = 0;
+
+ * core.c (read_memory): Don't do anything if length is 0.
+
+ * Makefile: Added readline.c to the list of files screwed by
+ having the ansi ioctl.h compilation with gcc.
+
+ * config.gdb: Added sun4os3 & sun4-os3 as availible options.
+
+Wed Jun 28 02:01:26 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu)
+
+ * command.c (lookup_cmd): Add ignore_help_classes argument.
+ (lookup_cmd_1): Add ignore_help_classes argument.
+ command.c, main.c: Change callers of lookup_cmd{,_1} to supply
+ value for ignore_help_classes.
+
+Tue Jun 27 18:01:31 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * utils.c (print_spaces_filtered): Made more efficient.
+ * defs.h: Declaration.
+ * valprint.c (val_print): Used in a couple of new places.
+
+Mon Jun 26 18:27:28 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * m68k-pinsn.c (print_insn_arg ['#', '^']): Combined them into one
+ case which always gets the argument from the word immediately
+ following the instruction.
+ (print_insn_arg ["[lL]w"]): Make sure to always get the register
+ mask from the word immediately following the instruction.
+
+Sun Jun 25 19:14:56 1989 Randall Smith (randy at galapas.ai.mit.edu)
+
+ * Makefile: Added hp-include back in as something to distribute.
+
+ * stack.c (print_block_frame_locals): Return value changed from
+ void to int; return 1 if values printed. Use _filtered.
+ (print_frame_local_vars): Use return value from
+ print_block_frame_locals to mention if nothing printed; mention
+ lack of symbol table, use _filtered.
+ (print_frame_arg_vars): Tell the user if no symbol table
+ or no values printed. Use fprintf_filtered instead of fprintf.
+ * blockframe.c (get_prev_frame_info): Check for no inferior or
+ core file before crashing.
+
+ * inflow.c (inferior_died): Set current frame to zero to keep from
+ looking like we're in start.
+
+Sat Jun 24 15:50:53 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * stack.c (frame_command): Added a check to make sure that there
+ was an inferior or a core file.
+
+ * expread.y (yylex): Allow floating point numbers of the form ".5"
+ to be parsed.
+
+ Changes by David Taylor at TMC:
+ * ns32k-pinsn.c: Added define for ?floating point coprocessor? and
+ tables for register names to be used for each of the possibilities.
+ (list_search): Created; searches a list of options for a specific
+ value.
+ (print_insn_arg): Added 'Q', 'b', 'M', 'P', 'g', and 'G' options
+ to the value location switch.
+ * ns32k-opcode.h: Added several new location flags.
+ [addr, enter, exit, ext[bwd], exts[bwd], lmr, lpr[bwd], restore,
+ rett, spr[bwd], smr]: Improved insn format output.
+
+ * symtab.c (list_symbols): Rearrange printing to produce readable
+ output for "info types".
+
+ * eval.c (evaluate_subexp_for_address): Fixed typo.
+
+ * dbxread.c (read_type): Don't output an error message when
+ there isn't a ',' after a cross-reference.
+
+ * dbxread.c (read_dbx_symtab): #if'd out N_FN case in
+ read_dbx_symtab if it has the EXT bit set (otherwise multiple
+ cases with the same value).
+
+Fri Jun 23 13:12:08 1989 Randall Smith (randy at plantaris.ai.mit.edu)
+
+ * symmisc.c: Changed decl of print_spaces from static to extern
+ (since it's defined in utils.c).
+
+ * remote.c (remote_open): Close remote_desc if it's already been
+ opened.
+
+ * Remote_Makefile, remote_gutils.c, remote_inflow.c,
+ remote_server.c, remote_utils.c: Combined into remote-multi.shar.
+ * remote-multi.shar: Created (Vikram Koka's remote stub).
+ * remote-sa.m68k.shar: Created (Glenn Engel's remcom.c).
+ * README: Updated to reflect new organization of remote stubs.
+
+ * dbxread.c (read_dbx_symtab): Put an N_FN in with N_FN | N_EXT to
+ account for those machines which don't use the external bit here.
+ Sigh.
+
+ * m-symmetry.h: Defined NO_SIGINTERRUPT.
+
+Thu Jun 22 12:51:37 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * printcmd.c (decode_format): Make sure characters are printed
+ using a byte size.
+
+ * utils.c (error): Added a terminal_ours here.
+
+ * stack.c (locals_info): Added check for selected frame.
+
+ * dbxread.c (read_type): Checked to make sure that a "," was
+ actually found in the symbol to end a cross reference.
+
+Wed Jun 21 10:30:01 1989 Randy Smith (randy at tartarus.uchicago.edu)
+
+ * expread.y (parse_number, [exp]): Allowed for the return of a
+ number marked as unsigned; this will allow inclusion of unsigned
+ constants.
+
+ * symtab.h: Put in default definitions for BUILTIN_TYPE_LONGEST
+ and BUILTIN_TYPE_UNSIGNED_LONGEST.
+
+ * expread.y (parse_number): Will now accept integers suffixed with
+ a 'u' (though does nothing special with it).
+
+ * valarith.c (value_binop): Added cases to deal with unsigned
+ arithmetic correctly.
+
+Tue Jun 20 14:25:54 1989 Randy Smith (randy at tartarus.uchicago.edu)
+
+ * dbxread.c (psymtab_to_symtab_1): Changed reading in info message
+ to go through printf_filtered.
+
+ * symtab.c (list_symbols): Placed header message after all calls
+ to psymtab_to_symtab.
+
+ * symtab.c (smash_to_{function, reference, pointer}_type): Carried
+ attribute of permanence for the type being smashed over the bzero
+ and allowed any type to point at this one if it is permanent.
+
+ * symtab.c (smash_to_{function, reference, pointer}_type): Fix
+ typo: check flags of to_type instead of type.
+
+ * m-hp9k320.h: Changed check on __GNU__ predefine to __GNUC__.
+
+ * Makefile: Made MUNCH_DEFINE seperate and based on SYSV_DEFINE;
+ they aren't the same on hp's.
+
+Mon Jun 19 17:10:16 1989 Randy Smith (randy at tartarus.uchicago.edu)
+
+ * Makefile: Fixed typo.
+
+ * valops.c (call_function): Error if the inferior has not been
+ started.
+
+ * ns32k-opcode.h [check[wc], cmpm[bwd], movm[bwd], skpsb]: Fixed
+ typos.
+
+Fri Jun 9 16:23:04 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * m-news.h [NO_SIGINTERRUPT]: Defined.
+
+ * dbxread.c (read_type): Start copy of undefined structure name
+ past [sue] defining type of cross ref.
+
+ * dbxread.c (process_one_symbol): Changed strchr to index.
+
+ * ns32k-opcode.h, ns32k-pinsn.c: More changes to number of
+ operands, addition of all of the set condition opcodes, addition
+ of several flag letters, all patterned after the gas code.
+
+ * ns32k-opcode.h [mov{su,us}[bwd], or[bwd]]: Changed number of
+ operands from 1 to 2.
+
+Wed Jun 7 15:04:24 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * symseg.h [TYPE_FLAG_STUB]: Created.
+ * dbxread.c (read_type): Set flag bit if type is stub.
+ (cleanup_undefined_types): Don't mark it as a stub if it's been
+ defined since we first learned about it.
+ * valprint.c (val_print): Print out a message to that effect if
+ this type is encountered.
+
+ * symseg.h, symtab.h: Moved the definition of TYPE_FLAG_PERM over
+ to symseg.h so that all such definitions would be in the same place.
+
+ * valprint.c (val_print): Print out <No data fields> for a
+ structure if there aren't any.
+
+ * dbxread.c (read_type): Set type name of a cross reference type
+ to "struct whatever" or something.
+
+Tue Jun 6 19:40:52 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * breakpoint.c (breakpoint_1): Print out symbolic location of
+ breakpoints for which there are no debugging symbols.
+
+Mon Jun 5 15:14:51 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * command.c (help_cmd_list): Made line_size static.
+
+Sat Jun 3 17:33:45 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * Makefile: Don't include the binutils hp-include directory in the
+ distribution anymore; refer the users to the binutils distribution.
+
+Thu Jun 1 16:33:07 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * printcmd.c (disable_display_command): Fixed loop iteration for
+ no arg case.
+
+ * printcmd.c (disable_display_command): Added from_tty parameter
+ to function.
+
+ * valops.c (value_of_variable): Call read_var_value with 0 cast to
+ FRAME instead of CORE_ADDR.
+
+ * eval.c (evaluate_subexp): Corrected number of args passed to
+ value_subscript (to 2).
+
+ * infrun.c (wait_for_inferior), symtab.c (decode_line_1),
+ m-convex.h: Changed name of FIRSTLINE_DEBUG_BROKEN to
+ PROLOGUE_FIRSTLINE_OVERLAP.
+
+ * m-merlin.h: Fixed typo.
+ * ns32k-opcode.h: Added ns32381 opcodes and "cinv" insn, and fixed
+ errors in movm[wd], rett, and sfsr.
+
+ * eval.c (evaluate_subexp, evaluate_subexp_for_address), valops.c
+ (value_zero): Change value_zero over to taking two arguments
+ instead of three.
+
+ * eval.c (evaluate_subexp)
+ [OP_VAR_VALUE]: Get correct lval type for AVOID_SIDE_EFFECTS for
+ all types of symbols.
+ [BINOP_DIV]: Don't divide if avoiding side effects; just return
+ an object of the correct type.
+ [BINOP_REPEAT]: Don't call value_repeat, just allocate a
+ repeated value.
+ (evaluete_subexp_for_address) [OP_VAR_VALUE]: Just return a thing
+ of the right type (after checking to make sure that we are allowed
+ to take the address of whatever variable has been passed).
+
+Mon May 29 11:01:02 1989 Randall Smith (randy at galapas.ai.mit.edu)
+
+ * breakpoint.c (until_break_command): Set the breakpoint with a
+ frame specification so that it won't trip in inferior calls to the
+ function. Also set things up so that it works based on selected
+ frame, not current one.
+
+Sun May 28 15:05:33 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * eval.c (evalue_subexp): Change subscript case to use value_zero
+ in EVAL_AVOID_SIDE_EFFECTS case.
+
+Fri May 26 12:03:56 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (read_addl_syms, psymtab_to_symtab): Removed
+ cleanup_undefined_types; this needs to be done on a symtab basis.
+ (end_symtab): Called cleanup_undefined_types from here.
+ (cleanup_undefined_types): No longer uses lookup_symbol (brain
+ dead idea; oh, well), now it searches through file_symbols.
+
+Wed May 24 15:52:43 1989 Randall Smith (randy at galapas)
+
+ * source.c (select_source_symtab): Only run through
+ partial_symtab_list if it exists.
+
+ * coffread.c (read_coff_symtab): Don't unrecord a misc function
+ when a function symbol is seen for it.
+
+ * expread.y [variable]: Make sure to write a type for memvals if
+ you don't get a mft you recognize.
+
+Tue May 23 12:15:57 1989 Randall Smith (randy at plantaris.ai.mit.edu)
+
+ * dbxread.c (read_ofile_symtab, psymtab_to_symtab): Moved cleanup
+ of undefined types to psymtab_to_symtab. That way it will be
+ called once for all readins (which will, among other things,
+ help reduce infinite loops).
+
+ * symtab.h [misc_function_type]: Forced mf_unknown to 0.
+ * dbxread.c (record_misc_function): Cast enum to unsigned char (to
+ fit).
+ * expread.y [variable]: Cast unsigned char back to enum to test.
+
+Mon May 22 13:08:25 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ Patches by John Gilmore for dealing well with floating point:
+ * findvar.c (value_from_register, locate_var_value): Used
+ BYTES_BIG_ENDIAN instead of an inline test.
+ * m-sparc.h [IEEE_FLOAT]: Created to indicate that the sparc is
+ IEEE compatible.
+ * printcmd.c (print_scalar_formatted): Use BYTES_BIG_ENDIAN and
+ the stream argument for printing; also modify default type for
+ 'f'. Change handling of invalid floats; changed call syntax for
+ is_nan.
+ (print_command): Don't print out anything indicating that
+ something was recorded on the history list if it wasn't.
+ * valprint.c (val_print): Fixed to deal properley with new format
+ of is_nan and unpacking doubles without errors occuring.
+ (is_nan): Changed argument list and how it figures big endianness
+ (uses macros).
+ * values.c (record_latest_value): Return -1 and don't record if
+ it's an invalid float.
+ (value_as_double): Changed to use new unpack_double calling
+ convention.
+ (unpack_double): Changed not to call error if the float was
+ invalid; simply to set invp and return. Changed calling syntax.
+ (unpack_field_as_long, modify_field): Changed to use
+ BITS_BIG_ENDIAN to determine correct action.
+
+ * m-hp9k320.h [HP_OS_BUG]: Created; deals with problem where a
+ trap happens after a continue.
+ * infrun.c (wait_for_inferior): Used.
+
+ * m-convex.h [FIRSTLINE_DEBUG_BROKEN]: Defined a flag to indicate
+ that the debugging symbols output by the compiler for the first
+ line of a function were broken.
+ * infrun.c (wait_for_inferior), symtab.c (decode_line_1): Used.
+
+ * gdb.texinfo [Data, Memory]: Minor cleanups of phrasing.
+
+Fri May 19 00:16:59 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (add_undefined_type, cleanup_undefined_types): Created
+ to keep a list of cross references to as yet undefined types.
+ (read_type): Call add_undefined_type when we run into such a case.
+ (read_addl_syms, read_ofile_symtab): Call cleanup_undefined_types
+ when we're done.
+
+ * dbxread.c (psymtab_to_symtab, psymtab_to_symtab_1): Broke
+ psymtab_to_symtab out into two routines; made sure the string
+ table was only readin once and the globals were only scanned once,
+ for any number of dependencies.
+
+Thu May 18 19:59:18 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * m-*.h: Defined (or not, as appropriate per machine)
+ BITS_BIG_ENDIAN, BYTES_BIG_ENDIAN, and WORDS_BIG_ENDIAN.
+
+Wed May 17 13:37:45 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * main.c (symbol_completion_function): Always complete on result
+ command list, even if exact match found. If it's really an exact
+ match, it'll find it again; if there's something longer than it,
+ it'll get the right result.
+
+ * symtab.c (make_symbol_completion_function): Fixed typo; strcmp
+ ==> strncmp.
+
+ * dbxread.c (read_dbx_symtab): Change 'G' case to mark symbols as
+ LOC_EXTERNAL.
+
+ * expread.y [variables]: Changed default type of text symbols to
+ function returning int so that one can use, eg. strcmp.
+
+ * infrun.c (wait_for_inferior): Include a special flag indicating
+ that one shouldn't insert the breakpoints on the next step for
+ returning from a sigtramp and forcing at least one move forward.
+
+ * infrun.c (wait_for_inferior): Change test for nexting into a
+ function to check for current stack pointer inner than previous
+ stack pointer.
+
+ * infrun.c (wait_for_inferior): Check for step resume break
+ address before dealing with normal breakpoints.
+
+ * infrun.c (wait_for_inferior): Added a case to deal with taking
+ and passing along a signal when single stepping past breakpoints
+ before inserting breakpoints.
+
+ * infrun.c (wait_for_inferior): Inserted special case to keep
+ going after taking a signal we are supposed to be taking.
+
+Tue May 16 12:49:55 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * inflow.c (terminal_ours_1): Cast result of signal to (int
+ (*)()).
+
+ * gdb.texinfo: Made sure that references to the program were in
+ upper case. Modify description of the "set prompt" command.
+ [Running]: Cleaned up introduction.
+ [Attach]: Cleaned up.
+ [Stepping]: Change "Proceed" to "Continue running" or "Execute".
+ Minor cleanup.
+ [Source Path]: Cleaned up intro. Cleared up distinction between
+ the executable search path and the source path. Restated effect
+ of the "directory" command with no arguments.
+ [Data]: Fixed typos and trivial details.
+ [Stepping]: Fixed up explanation of "until".
+
+ * source.c (print_source_lines): Print through filter.
+
+ * printcmd.c (x_command): If the format with which to print is
+ "i", use the address of anything that isn't a pointer instead of
+ the value. This is for, eg. "x/10i main".
+
+ * gdb.texinfo: Updated last modification date on manual.
+
+Mon May 15 12:11:33 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * symtab.c (lookup_symtab): Fixed typo (name ==> copy) in call to
+ lookup_symtab_1.
+
+ * gdb.texinfo: Added documentation for "break [+-]n" and for new
+ actions of "directory" command (taking multiple directory names at
+ the same time).
+
+ * m68k-opcode.h: Replaced the version in gdb with an up-to-date
+ version from the assembler directory.
+ * m68k-pinsn.c (print_insn_arg): Added cases 'l' & 'L' to switch
+ to print register lists for movem instructions.
+
+ * dbxread.c, m-convex.h: Moved convex dependent include files over
+ from dbxread.c to m-convex.h.
+
+ * printcmd.c (disable_display, disable_display_command): Changed
+ name of first to second, and created first which takes an int as
+ arg rather than a char pointer. Changed second to use first.
+ (_initialize_printcmd): Changed to use second as command to call.
+ (delete_current_display, disable_current_display): Changed name of
+ first to second, and changed functionality to match.
+ * infrun.c (normal_stop), main.c (return_to_top_level): Changed to
+ call disable_current_display.
+
+ * dbxread.c (process_one_symbol, read_dbx_symtab): Changed N_FN to
+ be N_FN | N_EXT to deal with new Berkeley define; this works with
+ either the old or the new.
+
+ * Remote_Makefile, remote_gutils.c, remote_inflow.c,
+ remote_server.c, remote_utils.c: Created.
+ * Makefile: Included in tag and tar files.
+ * README: Included a note about them.
+
+ * printcmd.c (print_address): Use find_pc_partial_function to
+ remove need to readin symtabs for symbolic addresses.
+
+ * source.c (directory_command): Replaced function with new one
+ that can accept lists of directories seperated by spaces or :'s.
+
+ * inflow.c (new_tty): Replaced calls to dup2 with calls to dup.
+
+Sun May 14 12:33:16 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * stack.c (args_info): Make sure that you have an inferior or core
+ file before taking action.
+
+ * ns32k-opcode.h [deiw, deid]: Fixed machine code values for these
+ opcodes.
+
+ * dbxread.c (scan_file_globals): Modified to use misc function
+ vector instead of file itself. Killed all arguments to the
+ funciton; no longer needed.
+ (psymtab_to_symtab): Changed call for above to reflect new (void)
+ argument list.
+
+ * dbxread.c (read_dbx_symtab, ): Moved HASH_OFFSET define out of
+ read_dbx_symtab.
+
+ * expread.y [variable]: Changed default type of misc function in
+ text space to be (void ()).
+
+ * Makefile: Modified for proper number of s/r conflicts (order is
+ confusing; the mod that necessitated this change was on May 12th,
+ not today).
+
+ * expread.y (yylex): Added SIGNED, LONG, SHORT, and INT keywords.
+ [typename]: Created.
+ [typebase]: Added rules for LONG, LONG INT, SHORT, SHORT INT,
+ SIGNED name, and UNSIGNED name (a good approximation of ansi
+ standard).
+
+ * Makefile: Included .c.o rule to avoid sun's make from throwing
+ any curves at us.
+
+ * blockframe.c: Included <obstack.h>
+
+ * command.c (lookup_cmd): Clear out trailing whitespace.
+
+ * command.c (lookup_cmd_1): Changed malloc to alloca.
+
+Fri May 12 12:13:12 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * printcmd.c (print_frame_args): Only print nameless args when you
+ know how many args there are supposed to be and when you've
+ printed fewer than them. Don't print nameless args between
+ printed args.
+
+ * symtab.c (make_symbol_completion_function): Fixed typo (= ==>
+ ==).
+
+ * remote.c (remote_open): ifdef'd out siginterrupt call by #ifndef
+ NO_SIGINTERRUPT.
+ * m-umax.h: Defined NO_SIGINTERRUPT.
+
+ * expread.y [ptype, array_mod, func_mod, direct_abs_decl,
+ abs_decl]: Added rules for parsing and creating arbitrarily
+ strange types for casts and sizeofs.
+
+ * symtab.c, symtab.h (create_array_type): Created. Some minor
+ misfeatures; see comments for details (main one being that you
+ might end up creating two arrays when you only needed one).
+
+Thu May 11 13:11:49 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * valops.c (value_zero): Add an argument for type of lval.
+ * eval.c (evaluate_subexp_for_address): Take address properly in
+ the avoid side affects case (ie. keep track of whether we have an
+ lval in memory and we can take the address).
+ (evaluate_subexp): Set the lval type of expressions created with
+ value_zero properley.
+
+ * valops.c, value.h (value_zero): Created--will return a value of
+ any type with contents filled with zero.
+ * symtab.c, symtab.h (lookup_struct_elt_type): Created.
+ * eval.c (evaluate_subexp): Modified to not read memory when
+ called with EVAL_AVOID_SIDE_EFFECTS.
+
+ * Makefile: Moved dbxread.c ahead of coffread.c in the list of
+ source files.
+
+Wed May 10 11:29:19 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * munch: Make sure that sysv version substitutes for the whole
+ line.
+
+ * symtab.h: Created an enum misc_function_type to hold the type of
+ the misc function being recorded.
+ * dbxread.c (record_misc_function): Branched on dbx symbols to
+ decide which type to assign to a misc function.
+ * coffread.c (record_misc_function): Always assign type unknown.
+ * expread.y [variable]: Now tests based on new values.
+
+Tue May 9 13:03:54 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * symtab.c: Changed inclusion of <strings.h> (doesn't work on
+ SYSV) to declaration of index.
+
+ * Makefile: Changed last couple of READLINE_FLAGS SYSV_DEFINE
+
+ * source.c ({forward, reverse}_search_command): Made a default
+ search file similar to for the list command.
+
+Mon May 8 18:07:51 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * printcmd.c (print_frame_args): If we don't know how many
+ arguments there are to this function, don't print the nameless
+ arguments. We don't know enough to find them.
+
+ * printcmd.c (print_frame_args): Call print_frame_nameless_args
+ with proper arguments (start & end as offsets from addr).
+
+ * dbxread.c (read_addl_syms): Removed cases to deal with global
+ symbols; this should all be done in scan_global_symbols.
+
+Sun May 7 11:36:23 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * Makefile: Added copying.awk to ${OTHERS}.
+
+Fri May 5 16:49:01 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * valprint.c (type_print_varspec_prefix): Don't pass
+ passed_a_pointer onto children.
+
+ * valprint.c (type_print_varspec_suffix): Print "array of" with
+ whatever the "of" is after tha array brackets.
+
+ * valprint.c (type_print_varspec_{prefix,suffix}): Arrange to
+ parenthesisze pointers to arrays as well as pointers to other
+ objects.
+
+ * valprint.c (type_print_varspec_suffix): Make sure to print
+ subscripts of multi-dimensional arrays in the right order.
+
+ * infcmd.c (run_command): Fixed improper usages of variables
+ within remote debugging branch.
+
+ * Makefile: Added Convex.notes to the list of extra files to carry
+ around.
+
+ * dbxread.c (symbol_file_command): Made use of alloca or malloc
+ dependent on macro define.
+
+Thu May 4 15:47:04 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * Makefile: Changed READLINE_FLAGS to SYSV_DEFINE and called munch
+ with it also.
+ * munch: Check first argument for -DSYSV and be looser about
+ picking up init routines if you find it.
+
+ * coffread.c: Made fclose be of type int.
+
+ * breakpoint.c (_initialize_breakpoint): Put "unset" into class
+ alias.
+
+Wed May 3 14:09:12 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * m-sparc.h [STACK_END_ADDR]: Parameterized off of
+ machine/vmparam.h (as per John Gilmore's suggestion).
+
+ * blockframe.c (get_prev_frame_info): Changed this function back
+ to checking frameless invocation first before checking frame
+ chain. This means that a backtrace up from start will produce the
+ wrong value, but that a backtrace from a frameless function called
+ in main will show up correctly.
+
+ * breakpoint.c (_initialize_breakpoint): Added entry in help for
+ delete that indicates that unset is an alias for it.
+
+ * main.c (symbol_completion_function): Modified recognition of
+ being within a single command.
+
+Tue May 2 15:13:45 1989 Randy Smith (randy at gnu)
+
+ * expread.y [variable]: Add some parens to get checking of the
+ misc function vector right.
+
+Mon May 1 13:07:03 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * default-dep.c (core_file_command): Made reg_offset unsigned.
+
+ * default-dep.c (core_file_command): Improved error messages for
+ reading in registers.
+
+ * expread.y: Allowed a BLOCKNAME to be ok for a variable name (as
+ per C syntax).
+
+ * dbxread.c (psymtab_to_symtab): Flushed stdout after printing
+ starting message about reading in symbols.
+
+ * printcmd.c (print_frame_args): Switched starting place for
+ printing of frameless args to be sizeof int above last real arg
+ printed.
+
+ * printcmd.c (print_frame_args): Modified final call to
+ print_nameless_args to not use frame slots used array if none had
+ been used.
+
+ * infrun.c (wait_for_inferior): Take FUNCTION_START_OFFSET into
+ account when dealing with comparison of pc values to function
+ addresses.
+
+ * Makefile: Added note about compiling gdb on a Vax running 4.3.
+
+Sun Apr 30 12:59:46 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * command.c (lookup_cmd): Got correct error message on bad
+ command.
+
+ * m-sun3.h [ABOUT_TO_RETURN]: Modified to allow any of the return
+ instructions, including trapv and return from interupt.
+
+ * command.c (lookup_cmd): If a command is found, use it's values
+ for error reporting and determination of needed subcommands.
+
+ * command.c (lookup_cmd): Use null string for error if cmdtype is
+ null; pass *line to error instead of **.
+
+ * command.c (lookup_cmd_1): End of command marked by anything but
+ alpha numeric or '-'. Included ctype.h.
+
+Fri Apr 28 18:30:49 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * source.c (select_source_symtab): Kept line number from ever
+ being less than 1 in main decode.
+
+Wed Apr 26 13:03:20 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * default-dep.c (core_file_command): Fixed typo.
+
+ * utils.c (fprintf_filtered): Don't use return value from
+ numchars.
+
+ * main.c, command.c (complete_on_cmdlist): Moved function to
+ command.c.
+
+ * command.c (lookup_cmd): Modified to use my new routine. Old
+ version is still there, ifdef'd out.
+
+ * command.c, command.h (lookup_cmd_1): Added a routine to do all
+ of the work of lookup_cmd with no error reporting and full return
+ of information garnered in search.
+
+Tue Apr 25 12:37:54 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * breakpoint.c (_initialize_breakpoint): Change "delete
+ breakpionts" to be in class alias and not have the abbrev flag
+ set.
+
+ * main.c (symbol_completion_function): Fix to correctly complete
+ things that correspond to multiword aliases.
+
+ * main.c (complete_on_cmdlist): Don't complete on something if it
+ isn't a command or prefix (ie. if it's just a help topic).
+
+ * main.c (symbol_completion_function): Set list index to be 0 if
+ creating a list with just one element.
+
+ * main.c (complete_on_cmdlist): Don't allow things with
+ abbrev_flag set to be completion values.
+ (symbol_completion_function): Don't accept an exact match if the
+ abbrev flag is set.
+
+ * dbxread.c (read_type): Fixed typo in comparision to check if
+ type number existed.
+
+ * dbxread.c (read_type): Made sure to only call dbx_lookup_type on
+ typenums if typenums were not -1.
+
+Mon Apr 24 17:52:12 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * symtab.c: Added strings.h as an include file.
+
+Fri Apr 21 15:28:38 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * symtab.c (lookup_partial_symtab): Changed to only return a match
+ if the name match is exact (which is what I want in all cases in
+ which this is currently used.
+
+Thu Apr 20 11:12:34 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * m-isi.h [REGISTER_U_ADDR]: Installed new version from net.
+ * default-dep.c: Deleted inclusion of fcntl.h; apparently not
+ necessary.
+ * Makefile: Added comment about compiling on isi under 4.3.
+
+ * breakpoint.c (break_command_1): Only give decode_line_1 the
+ default_breakpoint_defaults if there's nothing better (ie. make
+ the default be off of the current_source notes if at all
+ possible).
+
+ * blockframe.c (get_prev_frame_info): Clean up comments and
+ delete code ifdefed out around FRAMELESS_FUNCTION_INVOCATION test.
+
+ * remote.c: Added a "?" message to protocol.
+ (remote_open): Used at startup.
+ (putpkt): Read whatever garbage comes over the line until we see a
+ '+' (ie. don't treat garbage as a timeout).
+
+ * valops.c (call_function): Eliminated no longer appropriate
+ comment.
+
+ * infrun.c (wait_for_inferior): Changed several convex conditional
+ compilations to be conditional on CANNOT_EXECUTE_STACK.
+
+Wed Apr 19 10:18:17 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * printcmd.c (print_frame_args): Added code to attempt to deal
+ with arguments that are bigger than an int.
+
+ Continuation of Convex/Fortran changes:
+ * printcmd.c (print_scalar_formatted): Added leading zeros to
+ printing of large integers.
+ (address_info, print_frame_args): Added code to deal with
+ LOC_REF_ARG.
+ (print_nameless_args): Allow param file to specify a routine with
+ which to print typeless integers.
+ (printf_command): Deal with long long values well.
+ * stack.c (print_frame_arg_vars): Change to deal with LOC_REF_ARG.
+ * symmisc.c (print_symbol): Change to deal with LOC_REF_ARG.
+ * symseg.h: Added LOC_REF_ARG to enum address_class.
+ * symtab.c (lookup_block_symbol): Changed to deal with
+ LOC_REF_ARG.
+ * valarith.c (value_subscripted_rvalue): Created.
+ (value_subscript): Used above when app.
+ (value_less, value_equal): Change to cast to (char *) before doing
+ comparison, for machines where that casting does something.
+ * valops.c (call_function): Setup to deal with machines where you
+ cannot execute code on the stack segment.
+ * valprint.c (val_print): Make sure that array element size isn't
+ zero before printing. Set address of default array to address of
+ first element. Put in a couple of int cast. Removed some convex
+ specific code. Added check for endianness of machine in case of a
+ packed structure. Added code for printing typeless integers and
+ for LONG LONG's.
+ (set_maximum_command): Change to use parse_and_eval_address to get
+ argument (so can use expressions there).
+ * values.c (value_of_internalvar, set_internalvar_component,
+ set_internalvar, convenience_info): Add in hooks for trapped
+ internal vars.
+ (unpack_long): Deal with LONG_LONG.
+ (value_field): Remove LONGEST cast.
+ (using_struct_return): Fixed typo ENUM ==> UNION.
+ * xgdb.c (_initialize_xgdb): Make sure that specify_exec_file_hook
+ is not called unless we are setting up a windowing environ.
+
+Tue Apr 18 13:43:37 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ Various changes involved in 1) getting gdb to work on the convex,
+ and 2) Getting gdb to work with fortran (due to convex!csmith):
+ * convex-dep.c, convex-opcode.h, m-convex.h, convex-pinsn.c:
+ Created (or replaced with new files).
+ * Makefile: Add convex dependent files. Changed default flags to
+ gnu malloc to be CFLAGS.
+ * config.gdb: Added convex to list of machines.
+ * core.c (files_info): Added a FILES_INFO_HOOK to be used if
+ defined.
+ (xfer_core_file): Conditionalized compilation of xfer_core_file on
+ the macro XFER_CORE_FILE.
+ * coffread.c (record_misc_function): Made sure it zerod type field
+ (which is now being used; see next).
+ * dbxread.c: Included some convex dependent include files.
+ (copy_pending, fix_common_blocks): Created.
+ [STAB_REG_REGNUM, BELIEVE_PCC_PROMOTION]: Created default values;
+ may be overridden in m-*.h.
+ Included data structures for keeping track of common blocks.
+ (dbx_alloc_type): Modified; if called with negative 1's will
+ create a type without putting it into the type vector.
+ (read_dbx_symtab, read_addl_syms): Modified calls to
+ record_misc_function to include the new information.
+ (symbol_file_command, psymtab_to_symtab, add_file_command):
+ Modified reading in of string table to adapt to machines which
+ *don't* store the size of the string table in the first four bytes
+ of the string table.
+ (read_dbx_symtab, scan_file_globals, read_ofile_symtab,
+ read_addl_syms): Modified assignment of namestring to accept null
+ index into symtab as ok.
+ (read_addl_syms): Modified readin of a new object file to fiddle
+ with common blocks correctly.
+ (process_one_symbol): Fixed incorrect comment about convex. Get
+ symbols local to a lexical context from correct spot on a per
+ machine basis. Catch a bug in pcc which occaisionally puts an SO
+ where there should be an SOL. Seperate sections for N_BCOMM &
+ N_ECOMM.
+ (define_symbol): Ignore symbols with no ":". Use
+ STAB_REG_TO_REGNUM. Added support for function args calling by
+ reference.
+ (read_type): Only read type number if one is there. Remove old
+ (#if 0'd out) array code.
+ (read_array_type): Added code for dealing with adjustable (by
+ parameter) arrays half-heartedly.
+ (read_enum_type): Allow a ',' to end a list of values.
+ (read_range_type): Added code to check for long long.
+ * expread.y: Modified to use LONGEST instead of long where
+ necessary. Modified to use a default type of int for objects that
+ weren't in text space.
+ * findvar.c (locate_var_value, read_var_value): Modified to deal
+ with args passed by reference.
+ * inflow.c (create_inferior): Used CREATE_INFERIOR_HOOK if it
+ exists.
+ * infrun.c (attach_program): Run terminal inferior when attaching.
+ (wait_for_inferior): Removed several convex dependencies.
+ * main.c (float_handler): Created.
+ Made whatever signal indicates a stop configurable (via macro
+ STOP_SIGNAL).
+ (main): Setup use of above as a signal handler. Added check for
+ "-nw" in args already processed.
+ (command_line_input): SIGTSTP ==>STOP_SIGNAL.
+
+ * expread.y: Added token BLOCKNAME to remove reduce/reduce
+ conflict.
+ * Makefile: Change message to reflect new grammar.
+
+Mon Apr 17 13:24:59 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * printcmd.c (compare_ints): Created.
+ (print_frame_args): Modified to always print arguments in the
+ order in which they were found in the symbol table. Figure out
+ what apots are missing on the fly.
+
+ * stack.c (up_command): Error if no inferior or core file.
+
+ * m-i386.h, m-symmetry.h [FRAMELESS_FUNCTION_INVOCATION]: Created;
+ same as m68k.
+
+ * dbxread.c (define_symbol): Changed "desc==0" test to
+ "processing_gcc_compilation", which is the correct way to do it.
+
+Sat Apr 15 17:18:38 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * expread.y: Added precedence rules for arglists, ?:, and sizeof
+ to eliminate some shift-reduce conflicts.
+ * Makefile: Modified "Expect" message to conform to new results.
+
+Thu Apr 13 12:29:26 1989 Randall Smith (randy at plantaris.ai.mit.edu)
+
+ * inflow.c (terminal_init_inferior): Fixed typo in recent diff
+ installation; TIOGETC ==> TIOCGETC.
+
+ * m-vax.h, m-sun2.h, m-sun3.h, m-sparc.h, m-hp*.h, m-isi.h,
+ m-news.h [FRAMELESS_FUNCTION_INVOCATION]: Created macro with
+ appropriate definition.
+
+Wed Apr 12 15:30:29 1989 Randall Smith (randy at plantaris.ai.mit.edu)
+
+ * blockframe.c (get_prev_frame_info): Added in a macro to specify
+ when a "frame" is called without a frame pointer being setup.
+
+ * Makefile [clean]: Made sure to delete gnu malloc if it was being
+ used.
+
+Mon Apr 10 12:43:49 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (process_one_symbol): Reset within_function to 0 after
+ last RBRAC of a function.
+
+ * dbxread.c (read_struct_type): Changed check for filling in of
+ TYPE_MAIN_VARIANT of type.
+
+ * inflow.c (create_inferior): Conditionalized fork so that it
+ would be used if USG was defined and HAVE_VFORK was not defined.
+
+ * defs.h: Added comment about enum command_class element
+ class_alias.
+
+ * dbxread.c (process_one_symbol): Fixed a typo with interesting
+ implications for associative processing in the brain (':' ==> 'c').
+
+ * sparc-dep.c (isabranch): Changed name to isannulled, modified to
+ deal with coprocessor branches, and improved comment.
+ (single_step): Changed to trap at npc + 4 instead of pc +8 on
+ annulled branches. Changed name in call to isabranch as above.
+
+ * m-sun4os4.h (STACK_END_ADDRESS): Changed it to 0xf8000000 under
+ os 4.0.
+
+Sat Apr 8 17:04:07 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (process_one_symbol): In the case N_FUN or N_FNAME the
+ value being refered to is sometimes just a text segment variable.
+ Catch this case.
+
+ * infrun.c (wait_for_inferior), breakpoint.c
+ (breakpoint_stop_status): Move the selection of the frame to
+ inside breakpoint_stop_status so that the frame only gets selected
+ (and the symbols potentially read in) if the symbols are needed.
+
+ * symtab.c (find_pc_psymbol): Fixed minor misthough (pc >=
+ fucntion start, not >).
+
+ * breakpoint.c (_initialize_breakpoint): Change "delete" internal
+ help entry to simply refer to it being a prefix command (since the
+ list of subcommands is right there on a "help delete").
+
+Fri Apr 7 15:22:18 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * blockframe.c (find_pc_partial_function): Created; figures out
+ what function pc is in (name and address) without reading in any
+ new symbols.
+ * symtab.h: Added decl for above.
+ * infrun.c (wait_for_inferior): Used instead of
+ find_pc_function_start.
+ * stack.c (print_frame_info): Used instead of hand coding for same
+ thing.
+
+ * dbxread.c (psymtab_to_symtab): No longer patch readin pst's out
+ of the partial_symtab_list; need them there for some checks.
+ * blockframe.c (block_for_pc), source.c (select_source_symtab),
+ symtab.c (lookup_symbol, find_pc_symtab, list_symbols): Made extra
+ sure not to call psymtab_to_symtab with ->readin == 1, since these
+ psymtab now stay on the list.
+ * symtab.c (sources_info): Now distinguishes between psymtabs with
+ readin set and those with it not set.
+
+ * symtab.c (lookup_symtab): Added check through partial symtabs
+ for name with .c appended.
+
+ * source.c (select_source_symtab): Changed semantics a little so
+ that the argument means something.
+ * source.c (list_command), symtab.c (decode_line_1): Changed call
+ to select_source_symtab to match new conventions.
+
+ * dbxread.c (add_file_command): This command no longer selects a
+ symbol table to list from.
+
+ * infrun.c (wait_for_inferior): Only call find_pc_function (to
+ find out if we have debugging symbols for a function and hence if
+ we should step over or into it) if we are doing a "step".
+
+Thu Apr 6 12:42:28 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * main.c (command_line_input): Added a local buffer and only
+ copied information into the global main.c buffer when it is
+ appropriate for it to be saved (and repeated).
+ (dont_repeat): Only nail line when we are reading from stdin
+ (otherwise null lines won't repeat and what's in line needs to be
+ saved).
+ (read_command_lines): Fixed typo; you don't what to repeat when
+ reading command lines from the input stream unless it's standard
+ input.
+
+ John Gilmore's (gnu@toad.com) mods for USG gdb:
+ * inflow.c: Removed inclusion of sys/user.h; no longer necessary.
+ (, terminal_init_inferior, terminal_inferior, terminal_ours_1,
+ term_status_command, _initialize_inflow) Seperated out declaration
+ and usage of terminal mode structures based on the existence of
+ the individual ioctls.
+ * utils.c (request_quit): Restore signal handler under USG. If
+ running under USG initialize sys_siglist at run time (too much
+ variation between systems).
+
+Wed Apr 5 13:47:24 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ John Gilmore's (gnu@toad.com) mods for USG gdb:
+ * default-dep.c: Moved include of sys/user.h to after include of
+ a.out.h.
+ (store_inferior_registers): Fixed error message.
+ (core_file_command): Improved error messages from reading in of
+ u area in core file. Changed calculation of offset of registers
+ to account for some machines putting it in as an offset rather
+ than an absolute address. Changed error messages for reading of
+ registers from core file.
+
+ * coffread.c (read_file_hdr): Added final check for BADMAG macro
+ to use if couldn't recognize magic number.
+ * Makefile: Added explicit directions for alloca addition.
+ Included alloca.c in list of possible library files. Cleaned up
+ possible library usage. Included additional information on gcc
+ and include files.
+
+ * source.c, remote.c, inflow.c, dbxread.c, core.c, coffread.c:
+ Changed include of sys/fcntl.h to an include of fcntl.h (as per
+ posix; presumably this will break fewer machines. I hopw).
+ * README: Added a pointer to comments at top of Makefile.
+ * Makefile: Added a comment about machines which need fcntl.h in
+ sys.
+
+Tue Apr 4 11:29:04 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * valprint.c (set_prettyprint_command, set_unionprint_command,
+ format_info): Created.
+ (_initialize_valprint): Added to lists of commands.
+
+ * gdb.texinfo [Backtrace]: Added a section describing the format
+ if symbols have not yet been read in.
+
+ * valprint.c (val_print): Added code to prettyprint structures if
+ "prettyprint" is set and only to print unions below the top level
+ if "unionprint" is set.
+
+ * infcmd.c (registers_info), valprint.c (value_print, val_print):
+ Added argument to call to val_print indicating deptch of recursion.
+
+ * symtab.[ch] (find_pc_psymbol): Created; finds static function
+ psymbol with value nearest to but under value passed.
+ * stack.c (print_frame_info): Used above to make sure I have best
+ fit to pc value.
+
+ * symseg.h (struct partial_symbol): Added value field.
+ * dbxread.c (read_dbx_symtab): Set value field for partial symbols
+ saved (so that we can lookup static symbols).
+
+ * symtab.[ch] (find_pc_symtab): Changed to external.
+ * stack.c (select_frame): Call above to make sure that symbols for
+ a selected frame is readin.
+
+Mon Apr 3 12:48:16 1989 Randall Smith (randy at plantaris.ai.mit.edu)
+
+ * stack.c (print_frame_info): Modified to only print out full
+ stack frame info on symbols whose tables have been read in.
+ * symtab.c, symtab.h (find_pc_psymtab): Made function external;
+ above needed it.
+
+ * main.c (,set_verbose_command, initialize_main): Created a
+ variable "info_verbose" which says to talk it up in various and
+ sundry places. Added command to set this variable.
+ * gdb.texinfo (GDB Output): Added documentation on "set verbose"
+ and changed the name of the "Screen Output" section to "GDB
+ Output".
+ * dbxread.c (psymtab_to_symtab): Added information message about
+ symbol readin. Conditionalized on above.
+
+ * dbxread.c (define_symbol): Made an "i" constant be of class
+ LOC_CONST and an "r" constant be of class LOC_CONST_BYTES.
+
+ * README: Made a note about modifications which may be necessary
+ to the manual for this version of gdb.
+
+ * blockframe.c (get_prev_frame_info): Now we get saved address and
+ check for validity before we check for leafism. This means that
+ we will catch the fact that we are in start, but we will miss any
+ fns that start calls without an fp. This should be fine.
+
+ * m-*.h (FRAME_CHAIN): Modified to return 0 if we are in start.
+ This is usually a test for within the first object file.
+ * m-sparc.h (FRAME_CHAIN): The test here is simply if the fp saved
+ off the the start sp is 0.
+
+ * blockframe.c (get_prev_frame_info): Removed check to see if we
+ were in start. Screws up sparc.
+
+ * m-sparc.h (FRAME_FIND_SAVED_REGISTERS): Changed test for dummy
+ frame to not need frame to be innermost.
+
+ * gdb.texinfo: Added section on frameless invocations of functions
+ and when gdb can and can't deal with this.
+
+ * stack.c (frame_info): Disallowed call if no inferior or core
+ file; fails gracefully if truely bad stack specfication has been
+ given (ie. parse_frame_specification returns 0).
+
+Fri Mar 31 13:59:33 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * infrun.c (normal_stop): Changed references to "unset-env" to
+ "delete env".
+
+ * infcmd.c (_initialize_infcmd): Change reference to set-args in
+ help run to "set args".
+
+ * remote.c (getpkt): Allow immediate quit when reading from
+ device; it could be hung.
+
+ * coffread.c (process_coff_symbol): Modify handling of REG
+ parameter symbols.
+
+Thu Mar 30 15:27:23 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (symbol_file_command): Use malloc to allocate the
+ space for the string table in symbol_file_command (and setup a
+ cleanup for this). This allows a more graceful error failure if
+ there isn't any memory availible (and probably allows more memory
+ to be avail, depending on the machine).
+
+ Additional mods for handling GNU C++ (from Tiemann):
+ * dbxread.c (read_type): Added case for '#' type (method type, I
+ believe).
+ (read_struct_type): If type code is undefined, make the main
+ variant for the type be itself. Allow recognition of bad format
+ in reading of structure fields.
+ * eval.c (evaluate_subexp): Modify evaluation of a member of a
+ structure and pointer to same to make sure that the syntax is
+ being used correctly and that the member is being accessed correctly.
+ * symseg.h: Added TYPE_CODE_METHOD to enum type_code. Add a
+ pointer to an array of argument types to the type structure.
+ * symtab.c (lookout_method_type, smash_to_method_type): Created.
+ * symtab.h (TYPE_ARG_TYPES): Created.
+ * valops.c (call_function): Modified handling of methods to be the
+ same as handling of functions; no longer check for members.
+ * valprint.c (val_print, type_print_varspec_{prefix,suffix},
+ type_print_base): Added code to print method args correctly.
+ * values.c (value_virtual_fn_field): Modify access to virtual
+ function table.
+
+Wed Mar 29 13:19:34 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * findvar.c: Special cases for REGISTER_WINDOWS: 1) Return 0 if we
+ are the innermost frame, and 2) return the next frame in's value
+ if the SP is being looked for.
+
+ * blockframe.c (get_next_frame): Created; returns the next (inner)
+ frame of the called frame.
+ * frame.h: Extern delcaration for above.
+
+ * main.c (command_line_input): Stick null at end before doing
+ history expansion.
+
+Tue Mar 28 17:35:50 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (read_dbx_symtab): Added namestring assignment to
+ N_DATA/BSS/ABS case. Sigh.
+
+Sat Mar 25 17:49:07 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * expread.y: Defined YYDEBUG.
+
+Fri Mar 24 20:46:55 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * symtab.c (make_symbol_completion_list): Completely rewrote to
+ never call psymtab_to_symtab, to do a correct search (no
+ duplicates) through the visible symbols, and to include structure
+ and union fields in the things that it can match.
+
+Thu Mar 23 15:27:44 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (dbx_create_type): Created; allocates and inits space
+ for a type without putting it on the type vector lists.
+ (dbx_alloc_type): Uses above.
+
+ * Makefile: xgdb.o now produced by default rules for .o.c.
+
+Fri Mar 17 14:27:50 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * infrun.c: Fixed up inclusion of aouthdr.h on UMAX_PTRACE.
+
+ * Makefile, config.gdb: Added hp300bsd to potential
+ configurations.
+ * hp300bsd-dep.c, m-hp300bsd.h: Created.
+
+ * infrun.c (wait_for_inferior): Rewrote to do no access to
+ inferior until we make sure it's still there.
+
+ * inflow.c (inferior_died): Added a select to force the selected
+ frame to null when inferior dies.
+
+ * dbxread.c (symbol_file_command): free and zero symfile when
+ discarding symbols.
+
+ * core.c (xfer_core_file): Extended and cleaned up logic in
+ interpeting memory address.
+
+ * core.c (xfer_core_file): Extended opening comment.
+
+Thu Mar 16 15:39:42 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * coffread.c (symbol_file_command): Free symfile name when freeing
+ contents.
+
+ * blockframe.c (get_prev_frame_info): Added to fatal error message
+ to indicate that it should never happen.
+
+ * stack.c (frame_info): Printed out value of "saved" sp seperately
+ to call attention to the fact that it isn't stored in memory
+ anywhere; the actual previous frames address is printed.
+
+ * m-sparc.h (FRAME_FIND_SAVED_REGS): Set address of sp saved in
+ frame to value of fp (rather than value of sp in current frame).
+
+ * expread.y: Allow "unsigned" as a type itself, as well as a type
+ modifier.
+
+ * coffread.c: Added declaration for fclose
+
+Fri Mar 10 17:22:31 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * main.c (command_line_input): Checked for -1 return from
+ readline; indicates EOF.
+
+Fri Mar 3 00:31:27 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * remote.c (remote_open): Cast return from signal to (void (*)) to
+ avoid problems on machines where the return type of signal is (int
+ (*)).
+
+ * Makefile: Removed deletion of version control from it (users
+ will need it for their changes).
+
+Thu Mar 2 15:32:21 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * symmetry-dep.c (print_1167_regs): Print out effective doubles on
+ even number regs.
+ (fetch_inferior_registers): Get the floating point regs also.
+
+ * xgdb.c (do_command): Copied command before calling execute
+ command (so that execute_command wouldn't write into text space).
+
+ * copying.awk: Created (will produce copying.c as output when
+ given COPYING as input).
+ * Makefile: Used above to create copying.c.
+ * main.c: Took out info_warranty and info_copying.
+
+ * *.*: Changed copyright notice to use new GNU General Public
+ License (includes necessary changes to manual).
+
+ * xgdb.c (create_text_widget): Created text_widget before I create
+ the source and sink.
+ (print_prompt): Added fflush (stdout).
+
+ * Makefile: Added -lXmu to the compilation line for xgdb. Left
+ the old one there incase people still had R2.
+
+ * README: Added note about -gg format.
+
+ * remote.c (getpkt): Fixed typo; && ==> &.
+
+ * Makefile: Added new variable READLINE_FLAGS so that I could
+ force compilation of readline.c and history.c with -DSYSV on
+ system V machines. Mentioned in Makefile comments at top.
+
+Wed Mar 1 17:01:01 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * hp9k320-dep.c (store_inferior_registers): Fixed typo.
+
+Fri Feb 24 14:58:45 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * hp9k320-dep.c (store_inferior_registers,
+ fetch_inferior_registers): Added support for remote debugging.
+
+ * remote.c (remote_timer): Created.
+ (remote_open, readchar): Setup to timeout reads if they take
+ longer than "timeout". This allows one to debug how long such
+ things take.
+ (putpkt): Modified to print a debugging message (if such things
+ are enabled) each time it resends a packet.
+ (getpkt): Modified to make the variable CSUM unsigned and read it
+ CSUM with an & 0xff (presumably to deal with poor sign extension
+ on some machines). Also made c1 and c2 unsigned.
+ (remote_wait): Changed buffer to unsigned status.
+ (remote_store_registers, remote_write_bytes): Puts a null byte at
+ the end of the control string.
+
+ * infcmd.c (attach_command, detach_command, _initialize_infcmd):
+ Made attach_command and detach_command always availible, but
+ modified them to only allow device file attaches if ATTACH_DETACH
+ is not defined.
+
+ * gdb.texinfo: Added cross reference from attach command to remote
+ debugging.
+
+Thu Feb 23 12:37:59 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * remote.c (remote_close): Created to close the remote connection
+ and set the remote_debugging flag to 0.
+ * infcmd.c (detach_command): Now calls the above when appropriate.
+
+ * gdb.texinfo: Removed references to the ``Distribution'' section
+ in the copyright.
+
+ * main.c, utils.c (ISATTY): Created default defintions of this
+ macro which use isatty and fileno.
+ * utils.c (fprintf_filtered, print_spaces_filtered), main.c
+ (command_loop, command_line_input): Used this macro.
+ * m-news.h: Created a definition to override this one.
+
+ * utils.c (fprintf_filtered): Made line_size static (clueless).
+
+ * utils.c (fprintf_filtered): Changed max length of line printed
+ to be 255 chars or twice the format length.
+
+ * symmetry-dep.c, m-symmetry: Fixed typo (^L ==> ).
+
+ * printcmd.c (do_examine): Fixed typo (\n ==> \t).
+
+Wed Feb 22 16:00:33 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ Contributed by Jay Vosburgh (jay@mentor.cc.purdue.edu)
+ * m-symmetry.h, symmetry-dep.c: Created.
+ * Makefile: Added above in appropriate lists.
+ * config.gdb: Added "symmetry" target.
+
+ * utils.c (prompt_for_continue): Zero'd chars_printed also.
+
+ * utils.c (fprintf_filtered): Call prompt for continue instead of
+ doing it yourself.
+
+ * dbxread.c (read_dbx_symtab): Added code to conditionalize what
+ symbol type holds to "x.o" or "-lx" symbol that indicates the
+ beginning of a new file.
+
+Tue Feb 21 16:22:13 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * gdb.texinfo: Deleted @ignore block at end of file.
+
+ * findvar.c, stack.c: Changed comments that refered to "frame
+ address" to "frame id".
+
+ * findvar.c (locate_var_value): Modified so that taking the
+ address of an array generates an object whose type is a pointer to
+ the elements of the array.
+
+Sat Feb 18 16:35:14 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * gdb.texinfo: Removed reference to "!" as a shell escape
+ character. Added a section on controling screen output
+ (pagination); changing "Input" section to "User Interface"
+ section. Changed many inappropriate subsubsection nodes into
+ subsections nodes (in the readline and history expansion
+ sections).
+
+Fri Feb 17 11:10:54 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * utils.c (set_screensize_command): Created.
+ (_initialize_utils): Added above to setlist.
+
+ * main.c (main): Added check to see if ~/.gdbinit and .gdbinit
+ were the same file; only one gets read if so. Had to include
+ sys/stat.h for this.
+
+ * valprint.c (type_print_base): Changed calls to print_spaces to
+ print_spaces_filtered.
+
+ * main.c (command_line_input): Chaned test for command line
+ editing to check for stdin and isatty.
+
+ * main.c (command_loop): Call reinitialize_more_filter before each
+ command (if reading from stdin and it's a tty).
+ utils.c (initialize_more_filter): Changed name to
+ reinitialize_more_filter; killed arguments.
+ utils.c (_initialize_utils): Created; initialized lines_per_page
+ and chars_per_line here.
+
+ * utils.c (fprintf_filtered): Removed printing of "\\\n" after
+ printing linesize - 1 chars; assume that the screen display will
+ take care of that. Still watching that overflow.
+
+ * main.c: Created the global variables linesize and pagesize to
+ describe the number of chars per line and lines per page.
+
+Thu Feb 16 17:27:43 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * printcmd.c (do_examine, print_scalar_formatted, print_address,
+ whatis_command, do_one_display, ptype_command), valprint.c
+ (value_print, val_print, type_print_method_args, type_print_1,
+ type_print_derivation_info, type_print_varspec_suffix,
+ type_print_base), breakpoint.c (breakpoints_info, breakpoint_1),
+ values.c (history_info), main.c (editing_info, warranty_info,
+ copying_info), infcmd.c (registers_info), inflow.c
+ (term_status_command), infrun.c (signals_info), stack.c
+ (backtrace_command, print_frame_info), symtab.c (list_symbols,
+ output_source_filename), command.c (help_cmd, help_list,
+ help_command_list): Replaced calls to printf, fprintf, and putc
+ with calls to [f]printf_filtered to handle more processing.
+ Killed local more emulations where I noticed them.
+
+Wed Feb 15 15:27:36 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * defs.h, utils.c (initialize_more_filter, fprintf_filtered,
+ printf_filtered): Created a printf that will also act as a more
+ filter, prompting the user for a <return> whenever the page length
+ is overflowed.
+
+ * symtab.c (list_symbols): Elminated some code inside of an #if 0.
+
+Tue Feb 14 11:11:24 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * Makefile: Turned off backup versions for this file; it changes
+ too often.
+
+ * command.c (lookup_cmd, _initialize_command): Changed '!' so that
+ it was no longer a shell escape. "sh" must be used.
+
+ * main.c (command_line_input, set_history_expansion,
+ initialize_main): Turned history expansion on, made it the
+ default, and only execute it if the first character in the line is
+ a '!'.
+
+ * version.c, gdb.texinfo: Moved version to 3.2 (as usual, jumping
+ the gun some time before release).
+
+ * gdb.texinfo: Added sections (adapted from Brian's notes) on
+ command line editing and history expansion.
+
+ * main.c (set_command_editing, initialize_main): Modified name to
+ set_editing and modified command to "set editing".
+
+ * Makefile: Put in dependencies for READLINEOBJS.
+
+ * main.c (history_info, command_info): Combined into new command
+ info; deleted history_info.
+ (initialize_main): Deleted "info history" command; it was
+ interfering with the value history.
+
+ * coffread.c (enter_linenos): Modified to do bit copy instead of
+ pointer dereference, since the clipper machine can't handle having
+ longs on short boundaries.
+ (read_file_hdr): Added code to get number of syms for clipper.
+
+ * stack.c (return_command): Fixed method for checking when all of
+ the necessary frames had been popped.
+
+ * dbxread.c (read_dbx_symtab (ADD_PSYMBOL_TO_LIST)): Fixed typo in
+ allocation length.
+
+Mon Feb 13 10:03:27 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * dbxread.c (read_dbx_symtab): Split assignment to namestring into
+ several different assignments (so that it wouldn't be done except
+ when it had to be). Shortened switches and duplicated code to
+ produce the lowest possible execution time. Commented (at top of
+ switch) which code I duplicated.
+
+ * dbxread.c (read_dbx_symtab): Modified which variables were
+ register and deleted several variables which weren't used. Also
+ eliminated 'F' choice from subswitch, broke out strcmp's, reversed
+ compare on line 1986, and elminated test for !namestring[0]; it is
+ caught by following test for null index of ':'.
+
+Sun Feb 12 12:57:56 1989 Randall Smith (randy at plantaris.ai.mit.edu)
+
+ * main.c (gdb_completer_word_break_characters): Turned \~ into ~.
+
+Sat Feb 11 15:39:06 1989 Randall Smith (randy at plantaris.ai.mit.edu)
+
+ * symtab.c (find_pc_psymtab): Created; checks all psymtab's till
+ it finds pc.
+ (find_pc_symtab): Used; fatal error if psymtab found is readin
+ (should have been caught in symtab loop).
+ (lookup_symbol): Added check before scan through partial symtab
+ list for symbol name to be on the misc function vector (only if in
+ VAR_NAMESPACE). Also made sure that psymtab's weren't fooled with
+ if they had already been read in.
+ (list_symbols): Checked through misc_function_vector for matching
+ names if we were looking for functions.
+ (make_symbol_completion_list): Checked through
+ misc_function_vector for matching names.
+ * dbxread.c (read_dbx_symtab): Don't bother to do processing on
+ global function types; this will be taken care of by the
+ misc_function hack.
+
+ * symtab.h: Modified comment on misc_function structure.
+
+Fri Feb 10 18:09:33 1989 Randall Smith (randy at plantaris.ai.mit.edu)
+
+ * symseg.h, dbxread.c (read_dbx_symtab, init_psymbol_list,
+ start_psymtab, end_psymtab), coffread.c (_initialize_coff),
+ symtab.c (lookup_partial_symbol, list_symbols,
+ make_symbol_completion_list): Changed separate variables for
+ description of partial symbol allocation into a specific kind of
+ structure.
+
+ (read_dbx_symtab, process_symbol_for_psymtab): Moved most of
+ process_symbol_for_psymtab up into read_dbx_symtab, moved a couple
+ of symbol types down to the ingore section, streamlined (I hope)
+ code some, modularized access to psymbol lists.
+
+Thu Feb 9 13:21:19 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * main.c (command_line_input): Made sure that it could recognize
+ newlines as indications to repeat the last line.
+
+ * symtab.c (_initialize_symtab): Changed size of builtin_type_void
+ to be 1 for compatibility with gcc.
+
+ * main.c (initialize_main): Made history_expansion the default
+ when gdb is compiled with HISTORY_EXPANSION.
+
+ * readline.c, readline.h, history.c, history.h, general.h,
+ emacs_keymap.c, vi_keymap.c, keymaps.c, funmap.c: Made all of
+ these links to /gp/gnu/bash/* to keep them updated.
+ * main.c (initialize_main): Made default be command editing on.
+
+Wed Feb 8 13:32:04 1989 & Smith (randy at hobbes)
+
+ * dbxread.c (read_dbx_symtab): Ignore N_BSLINE on first
+ readthrough.
+
+ * Makefile: Removed convex-dep.c from list of distribution files.
+
+Tue Feb 7 14:06:25 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * main.c: Added command lists sethistlist and unsethistlist to
+ accesible command lists.
+ (parse_binary_operation): Created to parse a on/1/yes vs. off/0/no
+ spec.
+ (set_command_edit, set_history, set_history_expansion,
+ set_history_write, set_history_size, set_history_filename,
+ command_info, history_info): Created to allow users to control
+ various aspects of command line editing.
+
+ * main.c (symbol_creation_function): Created.
+ (command_line_input, initialize_main): Added rest of stuff
+ necessary for calling bfox' command editing routines under
+ run-time control.
+ * Makefile: Included readline and history source files for command
+ editing; also made arrangements to make sure that the termcap
+ library was available.
+ * symtab.c (make_symbol_completion_list): Created.
+
+Mon Feb 6 16:25:25 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * main.c: Invented variables to control command editing.
+ command_editing_p, history_expansion_p, history_size,
+ write_history_p, history_filename. Initialized them to default
+ values in initialize_main.
+
+ * infcmd.c (registers_info), infrun.c (signals_info),
+ * main.c (gdb_read_line): Changed name to command_line_input.
+ (readline): Changed name to gdb_readline; added second argument
+ indicating that the read value shouldn't be saved (via malloc).
+ * infcmd.c (registers_info), infrun.c (signals_info), main.c
+ (copying_info), symtab.c (output_source_filename, MORE,
+ list_symbols): Converted to use gdb_readline in place of
+ gdb_read_line.
+
+
+Sun Feb 5 17:34:38 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * blockframe.c (get_frame_saved_regs): Removed macro expansion
+ that had accidentally been left in the code.
+
+Sat Feb 4 17:54:14 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * main.c (gdb_read_line, readline): Added function readline and
+ converted gdb_read_line to use it. This was a conversion to the
+ line at a time style of input, in preparation for full command
+ editing.
+
+Fri Feb 3 12:39:03 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (read_dbx_symtab): Call end_psymtab at the end of
+ read_dbx_symtab if any psymtab still needs to be completed.
+
+ * config.gdb, sun3-dep.c: Brought these into accord with the
+ actual sun2 status (no floating point period; sun3-dep.c unless
+ has os > 3.0).
+ * m-sun2os2.h: Deleted; not needed.
+
+ * config.gdb: Added a couple of aliases for machines in the
+ script.
+
+ * infrun.c: Added inclusion of aouthdr.h inside of #ifdef UMAX
+ because ptrace needs to know about the a.out header.
+
+ * Makefile: Made dep.o depend on dep.c and config.status only.
+
+ * expread.y: Added declarations of all of the new write_exp_elt
+ functions at the include section in the top.
+
+ * Makefile: Added a YACC definition so that people can use bison
+ if they wish.
+
+ * Makefile: Added rms' XGDB-README to the distribution.
+
+ * Makefile: Added removal of init.o on a "make clean".
+
+Thu Feb 2 16:27:06 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * *-dep.c: Deleted definition of COFF_FORMAT if AOUTHDR was
+ defined since 1) We *may* (recent mail message) want to define
+ AOUTHDR under a basically BSD system, and 2) AOUTHDR is sometimes
+ a typedef in coff encapsulation setups. Also removed #define's of
+ AOUTHDR if AOUTHDR is already defined (inside of coff format).
+ * core.c, dbxread.c: Removed #define's of AOUTHDR if AOUTHDR is
+ already defined (inside of coff format).
+
+Tue Jan 31 12:56:01 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * GDB 3.1 released.
+
+ * values.c (modify_field): Changed test for endianness to assign
+ to integer and reference character (so that all bits would be
+ defined).
+
+Mon Jan 30 11:41:21 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * news-dep.c: Deleted inclusion of fcntl.h; just duplicates stuff
+ found in sys/file.h.
+
+ * i386-dep.c: Included default definition of N_SET_MAGIC for
+ COFF_FORMAT.
+
+ * config.gdb: Added checks for several different operating
+ systems.
+
+ * coffread.c (read_struct_type): Put in a flag variable so that
+ one could tell when you got to the end of a structure.
+
+ * sun3-dep.c (core_file_command): Changed #ifdef based on SUNOS4
+ to ifdef based on FPU.
+
+ * infrun.c (restore_inferior_status): Changed error message to
+ "unable to restore previously selected frame".
+
+ * dbxread.c (read_dbx_symtab): Used intermediate variable in error
+ message reporting a bad symbol type. (scan_file_globals,
+ read_ofile_symtab, read_addl_syms): Data type of "type" changed to
+ unsigned char (which is what it is).
+ * i386-dep.c: Removed define of COFF_FORMAT if AOUTHDR is defined.
+ Removed define of a_magic to magic (taken care of by N_MAGIC).
+ (core_file_command): Zero'd core_aouthdr instead of setting magic
+ to zero.
+ * i386-pinsn.c: Changed jcxz == jCcxz in jump table.
+ (putop): Added a case for 'C'.
+ (OP_J): Added code to handle possible masking of PC value on
+ certain kinds of data.
+ m-i386gas.h: Moved COFF_ENCAPSULATE to before inclusion of
+ m-i386.h and defined NAMES_HAVE_UNDERSCORE.
+
+ * coffread.c (unrecrod_misc_function, read_coff_symtab): Added
+ symbol number on which error occured to error output.
+
+Fri Jan 27 11:55:04 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * Makefile: Removed init.c in make clean. Removed it without -f
+ and with leading - in make ?gdb.
+
+Thu Jan 26 15:08:03 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ Changes to get it to work on gould NP1.
+ * dbxread.c (read_dbx_symtab): Included cases for N_NBDATA and
+ N_NBBSS.
+ (psymtab_to_symtab): Changed declaration of hdr to
+ DECLARE_FILE_HEADERS. Changed access to use STRING_TABLE_SIZE and
+ SYMBOL_TABLE_SIZE.
+ * gld-pinsn.c (findframe): Added declaration of framechain() as
+ FRAME_ADDR.
+
+ * coffread.c (read_coff_symtab): Avoided treating typedefs as
+ external symbol definitions.
+
+Wed Jan 25 14:45:43 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * Makefile: Removed reference to alloca.c. If they need it, they
+ can pull alloca.o from the gnu-emacs directory.
+
+ * version.c, gdb.texinfo: Updated version to 3.1 (jumping the gun
+ a bit so that I won't forget when I release).
+
+ * m-sun2.h, m-sun2os2.h, m-sun3os4.h, config.gdb: Modified code so
+ that default includes new sun core, ptrace, and attach-detach.
+ Added defaults for sun 2 os 2.
+
+ Modifications to reset stack limit back to what it used to be just
+ before exec. All mods inside of #ifdef SET_STACK_LIMIT_HUGE.
+ * main.c: Added global variable original_stack_limit.
+ (main): Set original_stack_limit to original stack limit.
+ * inflow.c: Added inclusion of necessary files and external
+ reference to original_stack_limit.
+ (create_inferior): Reset stack limit to original_stack_limit.
+
+ * dbxread.c (read_dbx_symtab): Killed PROFILE_SYMBOLS ifdef.
+
+ * sparc-dep.c (isabranch): Multiplied offset by 4 before adding it
+ to addr to get target.
+
+ * Makefile: Added definition of SHELL to Makefile.
+
+ * m-sun2os4.h: Added code to define NEW_SUN_PTRACE, NEW_SUN_CORE,
+ and ATTACH_DETACH.
+ * sun3-dep.c: Added code to avoid fp regs if we are on a sun2.
+
+Tue Jan 24 17:59:14 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (read_array_type): Added function.
+ (read_type): Added call to above instead of inline code.
+
+ * Makefile: Added ${GNU_MALLOC} to the list of dependencies for
+ the executables.
+
+Mon Jan 23 15:08:51 1989 Randall Smith (randy at plantaris.ai.mit.edu)
+
+ * gdb.texinfo: Added paragraph to summary describing languages
+ with which gdb can be run. Also added descriptions of the
+ "info-methods" and "add-file" commands.
+
+ * symseg.h: Commented a range type as having TYPE_TARGET_TYPE
+ pointing at the containing type for the range (often int).
+ * dbxread.c (read_range_type): Added code to do actual range types
+ if they are defined. Assumed that the length of a range type is
+ the length of the target type; this is a lie, but will do until
+ somebody gets back to me as to what these silly dbx symbols mean.
+
+ * dbxread.c (read_range_type): Added code to be more picky about
+ recognizing builtins as range types, to treat types defined as
+ subranges of themselves to be subranges of int, and to recognize
+ the char type idiom from dbx as a special case.
+
+Sun Jan 22 01:00:13 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * m-vax.h: Removed definition of FUNCTION_HAS_FRAME_POINTER.
+ * blockframe.c (get_prev_frame_info): Removed default definition
+ and use of above. Instead conditionalized checking for leaf nodes
+ on FUNCTION_START_OFFSET (see comment in code).
+
+Sat Jan 21 16:59:19 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (read_range_type): Fixed assumption that integer was
+ always type 1.
+
+ * gdb.texinfo: Fixed spelling mistake and added a note in the
+ running section making it clear that users may invoke subroutines
+ directly from gdb.
+
+ * blockframe.c: Setup a default definition for the macro
+ FUNCTION_HAS_FRAME_POINTER.
+ (get_prev_frame_info): Used this macro instead of checking
+ SKIP_PROLOGUE directly.
+ * m-vax.h: Overroad definition; all functions on the vax have
+ frame pointers.
+
+Fri Jan 20 12:25:35 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * core.c: Added default definition of N_MAGIC for COFF_FORMAT.
+
+ * xgdb.c: Installed a fix to keep the thing from dying when there
+ isn't any frame selected.
+
+ * core.c: Made a change for the UMAX system; needs a different
+ file included if using that core format.
+
+ * Makefile: Deleted duplicate obstack.h in dbxread.c dependency.
+
+ * munch: Modified (much simpler) to cover (I hope) all cases.
+
+ * utils.c (save_cleanups, restore_cleanups): Added functions to
+ allow you to push and pop the chain of cleanups to be done.
+ * defs.h: Declared the new functions.
+ * main.c (catch_errors): Made sure that the only cleanups which
+ would be done were the ones put on the chain *after* the current
+ location.
+
+ * m-*.h (FRAME_CHAIN_VALID): Removed check on pc in the current
+ frame being valid.
+ * blockframe.c (get_prev_frame_info): Made the assumption that if
+ a frame's pc value was within the first object file (presumed to
+ be /lib/crt0.o), that we shouldn't go any higher.
+
+ * infrun.c (wait_for_inferior): Do *not* execute check for stop pc
+ at step_resume_break if we are proceeding over a breakpoint (ie.
+ if trap_expected != 0).
+
+ * Makefile: Added -g to LDFLAGS.
+
+ * m-news.h (POP_FRAME) Fixed typo.
+
+ * printcmd.c (print_frame_args): Modified to print out register
+ params in order by .stabs entry, not by register number.
+
+ * sparc-opcode.h: Changed declaration of (struct
+ arith_imm_fmt).simm to be signed (as per architecture manual).
+ * sparc-pinsn.c (fprint_addr1, print_insn): Forced a cast to an
+ int, so that we really would get signed behaivior (default for sun
+ cc is unsigned).
+
+ * i386-dep.c (i386_get_frame_setup): Replace function with new
+ function provided by pace to fix bug in recognizing prologue.
+
+Thu Jan 19 11:01:22 1989 Randall Smith (randy at plantaris.ai.mit.edu)
+
+ * infcmd.c (run_command): Changed error message to "Program not
+ restarted."
+
+ * value.h: Changed "frame" field in value structure to be a
+ FRAME_ADDR (actually CORE_ADDR) so that it could survive across
+ calls.
+
+ * m-sun.h (FRAME_FIND_SAVED_REGS): Fixed a typo.
+
+ * value.h: Added lval: "lval_reg_frame_relative" to indicate a
+ register that must be interpeted relative to a frame. Added
+ single entry to value structure: "frame", used to indicate which
+ frame a relative regnum is relative to.
+ * findvar.c (value_from_register): Modified to correctly setup
+ these fields when needed. Deleted section to fiddle with last
+ register copied on little endian machine; multi register
+ structures will always occupy an integral number of registers.
+ (find_saved_register): Made extern.
+ * values.c (allocate_value, allocate_repeat_value): Zero frame
+ field on creation.
+ * valops.c (value_assign): Added case for lval_reg_frame_relative;
+ copy value out, modify it, and copy it back. Desclared
+ find_saved_register as being external.
+ * value.h: Removed addition of kludgy structure; thoroughly
+ commented file.
+ * values.c (free_value, free_all_values, clear_value_history,
+ set_internalvar, clear_internavars): Killed free_value.
+
+Wed Jan 18 20:09:39 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * value.h: Deleted struct partial_storage; left over from
+ yesterday.
+
+ * findvar.c (value_from_register): Added code to create a value of
+ type lval_reg_partsaved if a value is in seperate registers and
+ saved in different places.
+
+Tue Jan 17 13:50:18 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * value.h: Added lval_reg_partsaved to enum lval_type and
+ commented enum lval_type. Commented value structure.
+ Added "struct partial_register_saved" to value struct; added
+ macros to deal with structure to value.h.
+ * values.c (free_value): Created; special cases lval_reg_partsaved
+ (which has a pointer to an array which also needs to be free).
+ (free_all_values, clear_value_history, set_internalvar,
+ clear_internalvars): Modified to use free_values.
+
+ * m-sunos4.h: Changed name to sun3os4.h.
+ * m-sun2os4.h, m-sun4os4.h: Created.
+ * config.gdb: Added configuration entries for each of the above.
+ * Makefile: Added into correct lists.
+
+ * Makefile: Added dependencies on a.out.encap.h. Made
+ a.out.encap.h dependent on a.out.gnu.h and dbxread.c dependent on
+ stab.gnu.h.
+
+ * infrun.c, remote.c: Removed inclusion of any a.out.h files in
+ these files; they aren't needed.
+
+ * README: Added comment about bug reporting and comment about
+ xgdb.
+
+ * Makefile: Added note to HPUX dependent section warning about
+ problems if compiled with gcc and mentioning the need to add
+ -Ihp-include to CFLAGS if you compile on those systems. Added a
+ note about needing the GNU nm with compilers *of gdb* that use the
+ coff encapsulate feature also. * hp-include: Made symbolic link
+ over to /gp/gnu/binutils.
+
+ * Makefile: Added TSOBS NTSOBS OBSTACK and REGEX to list of things
+ to delete in "make clean". Also changed "squeakyclean" target as
+ "realclean".
+
+ * findvar.c (value_from_register): Added assignment of VALUE_LVAL
+ to be lval_memory when that is appropriate (original code didn't
+ bother because it assumed that it was working with a pre lval
+ memoried value).
+
+ * expread.y (yylex): Changed to only return type THIS if the
+ symbol "$this" is defined in some block superior or equal to the
+ current expression context block.
+
+Mon Jan 16 13:56:44 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * m-*.h (FRAME_CHAIN_VALID): On machines which check the relation
+ of FRAME_SAVED_PC (thisframe) to first_object_file_end (all except
+ gould), make sure that the pc of the current frame also passes (in
+ case someone stops in _start).
+
+ * findvar.c (value_of_register): Changed error message in case of
+ no inferior or core file.
+
+ * infcmd.c (registers_info): Added a check for inferior or core
+ file; error message if not.
+
+ * main.c (gdb_read_line): Modified to take prompt as argument and
+ output it to stdout.
+ * infcmd.c (registers_info, signals_info), main.c (command_loop,
+ read_command_lines, copying_info), symtab.c (decode_line_2,
+ output_source_filename, MORE, list_symbols): Changed calling
+ convention used to call gdb_read_line.
+
+ * infcmd.c, infrun.c, main.c, symtab.c: Changed the name of the
+ function "read_line" to "gdb_read_line".
+ * breakpoint.c: Deleted external referenced to function
+ "read_line" (not needed by code).
+
+Fri Jan 13 12:22:05 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * i386-dep.c: Include a.out.encap.h if COFF_ENCAPSULATE.
+ (N_SET_MAGIC): Defined if not defined by include file.
+ (core_file_command): Used N_SET_MAGIC instead of assignment to
+ a_magic.
+ (exec_file_command): Stuck in a HEADER_SEEK_FD.
+
+ * config.gdb: Added i386-dep.c as depfile for i386gas choice.
+
+ * munch: Added -I. to cc to pick up things included by the param
+ file.
+
+ * stab.gnu.def: Changed name to stab.def (stab.gnu.h needs this name).
+ * Makefile: Changed name here also.
+ * dbxread.c: Changed name of gnu-stab.h to stab.gnu.h.
+
+ * gnu-stab.h: Changed name to stab.gnu.h.
+ * stab.gnu.def: Added as link to binutils.
+ * Makefile: Put both in in the distribution.
+
+Thu Jan 12 11:33:49 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c: Made which stab.h is included dependent on
+ COFF_ENCAPSULATE; either <stab.h> or "gnu-stab.h".
+ * Makefile: Included gnu-stab.h in the list of files to include in
+ the distribution.
+ * gnu-stab.h: Made a link to /gp/gnu/binutils/stab.h
+
+ * Makefile: Included a.out.gnu.h and m-i386gas.h in list of
+ distribution files.
+ * m-i386gas.h: Changed to include m-i386.h and fiddle with it
+ instead of being a whole new file.
+ * a.out.gnu.h: Made a link to /gp/gnu/binutils/a.out.gnu.h.
+
+ Chris Hanson's changes to gdb for hp Unix.
+ * Makefile: Modified comments on hpux.
+ * hp9k320-dep.c: #define'd WOPR & moved inclusion of signal.h
+ * inflow.c: Moved around declaratiosn of <sys/fcntl.h> and
+ <sys/ioctl.h> inside of USG depends and deleted all SYSV ifdef's
+ (use USG instead).
+ * munch: Modified to accept any number of spaces between the T and
+ the symbol name.
+
+ Pace's changes to gdb to work with COFF_ENCAPSULATE (robotussin):
+ * config.gdb: Added i386gas to targets.
+ * default-dep.c: Include a.out.encap.h if COFF_ENCAPSULATE.
+ (N_SET_MAGIC): Defined if not defined by include file.
+ (core_file_command): Used N_SET_MAGIC instead of assignment to a_magic.
+ (exec_file_command): Stuck in a HEADER_SEEK_FD.
+ * infrun.c, remote.c: Added an include of a.out.encap.h if
+ COFF_ENCAPSULATE defined. This is commented out in these two
+ files, I presume because the definitions aren't used.
+ * m-i386gas.h: Created.
+ * dbxread.c: Included defintions for USG.
+ (READ_FILE_HEADERS): Now uses HEADER_SEEK_FD if it exists.
+ (symbol_file_command): Deleted use of HEADER_SEEK_FD.
+ * core.c: Deleted extra definition of COFF_FORMAT.
+ (N_MAGIC): Defined to be a_magic if not already defined.
+ (validate_files): USed N_MAGIC instead of reading a_magic.
+
+Wed Jan 11 12:51:00 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * remote.c: Upped PBUFSIZ.
+ (getpkt): Added zeroing of c inside loop in case of error retry.
+
+ * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Removed
+ code to not put stuff with debugging symbols in the misc function
+ list. Had been ifdef'd out.
+
+ * gdb.texinfo: Added the fact that the return value for a function
+ is printed if you use return.
+
+ * infrun.c (wait_for_inferior): Removed test in "Have we hit
+ step_resume_breakpoint" for sp values in proper orientation. Was
+ in there for recursive calls in functions without frame pointers
+ and it was screwing up calls to alloca.
+
+ * dbxread.c: Added #ifdef COFF_ENCAPSULATE to include
+ a.out.encap.h.
+ (symbol_file_command): Do HEADER_SEEK_FD when defined.
+ * dbxread.c, core.c: Deleted #ifdef ROBOTUSSIN stuff.
+ * robotussin.h: Deleted local copy (was symlink).
+ * a.out.encap.h: Created symlink to
+ /gp/gnu/binutils/a.out.encap.h.
+ * Makefile: Removed robotussin.h and included a.out.encap.h in
+ list of files.
+
+ * valprint.c (val_print, print_scalar_formatted): Changed default
+ precision of printing float value; now 6 for a float and 16 for a
+ double.
+
+ * findvar.c (value_from_register): Added code to deal with the
+ case where a value is spread over several registers. Still don't
+ deal with the case when some registers are saved in memory and
+ some aren't.
+
+Tue Jan 10 17:04:04 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * xgdb.c (xgdb_create_window): Removed third arg (XtDepth) to
+ frameArgs.
+
+ * infrun.c (handle_command): Error if signal number is less or
+ equal to 0 or greater or equal to NSIG or a signal number is not
+ provided.
+
+ * command.c (lookup_cmd): Modified to not convert command section
+ of command line to lower case in place (in case it isn't a
+ subcommand, but an argument to a command).
+
+Fri Jan 6 17:57:34 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c: Changed "text area" to "data area" in comments on
+ N_SETV.
+
+Wed Jan 4 12:29:54 1989 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * dbxread.c: Added definitions of gnu symbol types after inclusion
+ of a.out.h and stab.h.
+
+Mon Jan 2 20:38:31 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * eval.c (evaluate_subexp): Binary logical operations needed to
+ know type to determine whether second value should be evaluated.
+ Modified to discover type before binup_user_defined_p branch.
+ Also commented "enum noside".
+
+ * Makefile: Changed invocations of munch to be "./munch".
+
+ * gdb.texinfo: Updated to refer to current version of gdb with
+ January 1989 last update.
+
+ * coffread.c (end_symtab): Zero context stack when finishing
+ lexical contexts.
+ (read_coff_symtab): error if context stack 0 in ".ef" else case.
+
+ * m-*.h (FRAME_SAVED_PC): Changed name of argument from "frame" to
+ "FRAME" to avoid problems with replacement of "->frame" part of
+ macro.
+
+ * i386-dep.c (i386_get_frame_setup): Added codestream_get() to
+ move codestream pointer up to the correct location in "subl $X,
+ %esp" case.
+
+Sun Jan 1 14:24:35 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * valprint.c (val_print): Rewrote routine to print string pointed
+ to by char pointer; was producing incorrect results when print_max
+ was 0.
+
+Fri Dec 30 12:13:35 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Put
+ everything on the misc function list.
+
+ * Checkpointed distribution.
+
+ * Makefile: Added expread.tab.c to the list of things slated for
+ distribution.
+
+Thu Dec 29 10:06:41 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * stack.c (set_backtrace_limit_command, backtrace_limit_info,
+ bactrace_command, _initialize_stack): Removed modifications for
+ limit on backtrace. Piping the backtrace through an interuptable
+ "more" emulation is a better way to do it.
+
+Wed Dec 28 11:43:09 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * stack.c
+ (set_backtrace_limit_command): Added command to set a limit to the
+ number of frames for a backtrace to print by default.
+ (backtrace_limit_info): To print the current limit.
+ (backtrace_command): To use the limit.
+ (_initialize_stack): To initialize the limit to its default value
+ (30), and add the set and info commands onto the appropriate
+ command lists.
+
+ * gdb.texinfo: Documented changes to "backtrace" and "commands"
+ commands.
+
+ * stack.c (backtrace_command): Altered so that a negative argument
+ would show the last few frames on the stack instead of the first
+ few.
+ (_initialize_stack): Modified help documentation.
+
+ * breakpoint.c (commands_command): Altered so that "commands" with
+ no argument would refer to the last breakpoint set.
+ (_initialize_breakpoint): Modified help documentation.
+
+ * infrun.c (wait_for_inferior): Removed ifdef on Sun4; now you can
+ single step through compiler generated sub calls and will die if
+ you next off of the end of a function.
+
+ * sparc-dep.c (single_step): Fixed typo; "break_insn" ==> "sizeof
+ break_insn".
+
+ * m-sparc.h (INIT_EXTRA_FRAME_INFO): Set the bottom of a stack
+ frame to be the bottom of the stack frame inner from this, if that
+ inner one is a leaf node.
+
+ * dbxread.c (read_dbx_symtab): Check to make sure we don't add a
+ psymtab to it's own dependency list.
+
+ * dbxread.c (read_dbx_symtab): Modified check for duplicate
+ dependencies to catch them correctly.
+
+Tue Dec 27 17:02:09 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * m-*.h (FRAME_SAVED_PC): Modified macro to take frame info
+ pointer as argument.
+ * stack.c (frame_info), blockframe.c (get_prev_frame_info),
+ gld-pinsn.c (findframe), m-*.h (SAVED_PC_AFTER_CALL,
+ FRAME_CHAIN_VALID, FRAME_NUM_ARGS): Changed usage of macros to
+ conform to above.
+ * m-sparc.h (FRAME_SAVED_PC), sparc-dep.c (frame_saved_pc):
+ Changed frame_saved_pc to have a frame info pointer as an
+ argument.
+
+ * m-vax.h, m-umax.h, m-npl.h, infrun.c (wait_for_inferior),
+ blockframe.c (get_prev_frame_info): Modified SAVED_PC_AFTER_CALL
+ to take a frame info pointer as an argument.
+
+ * blockframe.c (get_prev_frame_info): Altered the use of the
+ macros FRAME_CHAIN, FRAME_CHAIN_VALID, and FRAME_CHAIN_COMBINE to
+ use frame info pointers as arguments instead of frame addresses.
+ * m-vax.h, m-umax.h, m-sun3.h, m-sun3.h, m-sparc.h, m-pn.h,
+ m-npl.h, m-news.h, m-merlin.h, m-isi.h, m-hp9k320.h, m-i386.h:
+ Modified definitions of the above macros to suit.
+ * m-pn.h, m-npl.h, gould-dep.c (findframe): Modified findframe to
+ use a frame info argument; also fixed internals (wouldn't work
+ before).
+
+ * m-sparc.h: Cosmetic changes; reordered some macros and made sure
+ that nothing went over 80 lines.
+
+Thu Dec 22 11:49:15 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * Version 3.0 released.
+
+ * README: Deleted note about changing -lobstack to obstack.o.
+
+Wed Dec 21 11:12:47 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * m-vax.h (SKIP_PROLOGUE): Now recognizes gcc prologue also.
+
+ * blockframe.c (get_prev_frame_info): Added FUNCTION_START_OFFSET
+ to result of get_pc_function_start.
+ * infrun.c (wait_for_inferior): Same.
+
+ * gdb.texinfo: Documented new "step" and "next" behavior in
+ functions without line number information.
+
+Tue Dec 20 18:00:45 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * infcmd.c (step_1): Changed behavior of "step" or "next" in a
+ function witout line number information. It now sets the step
+ range around the function (to single step out of it) using the
+ misc function vector, warns the user, and continues.
+
+ * symtab.c (find_pc_line): Zero "end" subsection of returned
+ symtab_and_line if no symtab found.
+
+Mon Dec 19 17:44:35 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * i386-pinsn.c (OP_REG): Added code from pace to streamline
+ disassembly and corrected types.
+ * i386-dep.c
+ (i386_follow_jump): Code added to follow byte and word offset
+ branches.
+ (i386_get_frame_setup): Expanded to deal with more wide ranging
+ function prologue.
+ (i386_frame_find_saved_regs, i386_skip_prologue): Changed to use
+ i386_get_frame_setup.
+
+
+Sun Dec 18 11:15:03 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * m-sparc.h: Deleted definition of SUN4_COMPILER_BUG; was designed
+ to avoid something that I consider a bug in our code, not theirs,
+ and which I fixed earlier. Also deleted definition of
+ CANNOT_USE_ARBITRARY_FRAME; no longer used anywhere.
+ FRAME_SPECIFICATION_DYADIC used instead.
+
+ * infrun.c (wait_for_inferior): On the sun 4, if a function
+ doesn't have a prologue, a next over it single steps into it.
+ This gets around the problem of a "call .stret4" at the end of
+ functions returning structures.
+ * m-sparc.h: Defined SUN4_COMPILER_FEATURE.
+
+ * main.c (copying_info): Seperated the last printf into two
+ printfs. The 386 compiler will now handle it.
+
+ * i386-pinsn.c, i386-dep.c: Moved print_387_control_word,
+ print_387_status_word, print_387_status, and i386_float_info to
+ dep.c Also included reg.h in dep.c.
+
+Sat Dec 17 15:31:38 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * main.c (source_command): Don't close instream if it's null
+ (indicating execution of a user-defined command).
+ (execute_command): Set instream to null before executing
+ commands and setup clean stuff to put it back on error.
+
+ * inflow.c (terminal_inferior): Went back to not checking the
+ ioctl returns; there are some systems when this will simply fail.
+ It seems that, on most of these systems, nothing bad will happen
+ by that failure.
+
+ * values.c (value_static_field): Fixed dereferencing of null
+ pointer.
+
+ * i386-dep.c (i386_follow_jump): Modified to deal with
+ unconditional byte offsets also.
+
+ * dbxread.c (read_type): Fixed typo in function type case of switch.
+
+ * infcmd.c (run_command): Does not prompt to restart if command is
+ not from a tty.
+
+Fri Dec 16 15:21:58 1988 Randy Smith (randy at calvin)
+
+ * gdb.texinfo: Added a third option under the "Cannot Insert
+ Breakpoints" workarounds.
+
+ * printcmd.c (display_command): Don't do the display unless there
+ is an active inferior; only set it.
+
+ * findvar.c (value_of_register): Added an error check for calling
+ this when the inferior isn't active and a core file isn't being
+ read.
+
+ * config.gdb: Added reminder about modifying REGEX in the
+ makefile for the 386.
+
+ * i386-pinsn.c, i386-dep.c: Moved m-i386.h helper functions over
+ to i386-dep.c.b
+
+Thu Dec 15 14:04:25 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * README: Added a couple of notes about compiling gdb with itself.
+
+ * breakpoint.c (set_momentary_breakpoint): Only takes FRAME_FP of
+ frame if frame is non-zero.
+
+ * printcmd.c (print_scalar_formatted): Implemented /g size for
+ hexadecimal format on machines without an 8 byte integer type. It
+ seems to be non-trivial to implement /g for other formats.
+ (decode_format): Allowed hexadecimal format to make it through /g
+ fileter.
+
+Wed Dec 14 13:27:04 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * expread.y: Converted all calls to write_exp_elt from the parser
+ to calls to one of write_exp_elt_{opcode, sym, longcst, dblcst,
+ char, type, intern}. Created all of these routines. This gets
+ around possible problems in passing one of these things in one ear
+ and getting something different out the other. Eliminated
+ SUN4_COMPILER_BUG ifdef's; they are now superfluous.
+
+ * symmisc.c (free_all_psymtabs): Reinited partial_symtab_list to 0.
+ (_initialize_symmisc): Initialized both symtab_list and
+ partial_symtab_list.
+
+ * dbxread.c (start_psymtab): Didn't allocate anything on
+ dependency list.
+ (end_psymtab): Allocate dependency list on psymbol obstack from
+ local list.
+ (add_psymtab_dependency): Deleted.
+ (read_dbx_symtab): Put dependency on local list if it isn't on it
+ already.
+
+ * symtab.c: Added definition of psymbol_obstack.
+ * symtab.h: Added declaration of psymbol_obstack.
+ * symmisc.c (free_all_psymtabs): Added freeing and
+ reinitionaliztion of psymbol_obstack.
+ * dbxread.c (free_all_psymbols): Deleted.
+ (start_psymtab, end_psymtab,
+ process_symbol_for_psymtab): Changed most allocation
+ of partial symbol stuff to be off of psymbol_obstack.
+
+ * symmisc.c (free_psymtab, free_all_psymtabs): Deleted
+ free_psymtab subroutine.
+
+ * symtab.h: Removed num_includes and includes from partial_symtab
+ structure; no longer needed now that all include files have their
+ own psymtab.
+ * dbxread.c (start_psymtab): Eliminated initialization of above.
+ (end_psymtab): Eliminated finalization of above; get
+ includes from seperate list.
+ (read_dbx_symtab): Moved includes from psymtab list to
+ their own list; included in call to end_psymtab.
+ * symmisc.c (free_psymtab): Don't free includes.
+
+Tue Dec 13 14:48:14 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * i386-pinsn.c: Reformatted entire file to correspond to gnu
+ software indentation conventions.
+
+ * sparc-dep.c (skip_prologue): Added capability of recognizign
+ stores of input register parameters into stack slots.
+
+ * sparc-dep.c: Added an include of sparc-opcode.h.
+ * sparc-pinsn.c, sparc-opcode.h: Moved insn_fmt structures and
+ unions from pinsn.c to opcode.h.
+ * sparc-pinsn.c, sparc-dep.c (isabranch, skip_prologue): Moved
+ this function from pinsn.c to dep.c.
+
+ * Makefile: Put in warnings about compiling with gcc (non-ansi
+ include files) and compiling with shared libs on Sunos 4.0 (can't
+ debug something that's been compiled that way).
+
+ * sparc-pinsn.c: Put in a completely new file (provided by
+ Tiemann) to handle floating point disassembly, load and store
+ instructions, and etc. better. Made the modifications this file
+ (ChangeLog) list for sparc-pinsn.c again.
+
+ * symtab.c (output_source_filename): Included "more" emulation hack.
+
+ * symtab.c (output_source_filename): Initialized COLUMN to 0.
+ (sources_info): Modified to not print out a line for
+ all of the include files within a partial symtab (since
+ they have pst's of their own now). Also modified to
+ make a distinction between those pst's read in and
+ those not.
+
+ * infrun.c: Included void declaration of single_step() if it's
+ going to be used.
+ * sparc-dep.c (single_step): Moved function previous to use of it.
+
+ * Makefile: Took removal of expread.tab.c out of make clean entry
+ and put it into a new "squeakyclean" entry.
+
+Mon Dec 12 13:21:02 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * sparc-pinsn.c (skip_prologue): Changed a struct insn_fmt to a
+ union insn_fmt.
+
+ * inflow.c (terminal_inferior): Checked *all* return codes from
+ ioctl's and fcntl's in routine.
+
+ * inflow.c (terminal_inferior): Added check for sucess of
+ TIOCSPGRP ioctl call. Just notifies if bad.
+
+ * dbxread.c (symbol_file_command): Close was getting called twice;
+ once directly and once through cleanup. Killed the direct call.
+
+Sun Dec 11 19:40:40 1988 & Smith (randy at hobbes.ai.mit.edu)
+
+ * valprint.c (val_print): Deleted spurious printing of "=" from
+ TYPE_CODE_REF case.
+
+Sat Dec 10 16:41:07 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * dbxread.c: Changed allocation of psymbols from using malloc and
+ realloc to using obstacks. This means they aren't realloc'd out
+ from under the pointers to them.
+
+Fri Dec 9 10:33:24 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * sparc-dep.c inflow.c core.c expread.y command.c infrun.c
+ infcmd.c dbxread.c symmisc.c symtab.c printcmd.c valprint.c
+ values.c source.c stack.c findvar.c breakpoint.c blockframe.c
+ main.c: Various cleanups inspired by "gcc -Wall" (without checking
+ for implicit declarations).
+
+ * Makefile: Cleaned up some more.
+
+ * valops.c, m-*.h (FIX_CALL_DUMMY): Modified to take 5 arguments
+ as per what sparc needs (programming for a superset of needed
+ args).
+
+ * dbxread.c (process_symbol_for_psymtab): Modified to be slightly
+ more picky about what it puts on the list of things *not* to be
+ put on the misc function list. When/if I shift everything over to
+ being placed on the misc_function_list, this will go away.
+
+ * inferior.h, infrun.c: Added fields to save in inferior_status
+ structure.
+
+ * maketarfile: Deleted; functionality is in Makefile now.
+
+ * infrun.c (wait_for_inferior): Modified algorithm for determining
+ whether or not a single-step was through a subroutine call. See
+ comments at top of file.
+
+ * dbxread.c (read_dbx_symtab): Made sure that the IGNORE_SYMBOL
+ macro would be checked during initial readin.
+
+ * dbxread.c (read_ofile_symtab): Added macro GCC_COMPILED_FLAG_SYMBOL
+ into dbxread.c to indicate what string in a local text symbol will
+ indicate a file compiled with gcc. Defaults to "gcc_compiled.".
+
+Thu Dec 8 11:46:22 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * m-sparc.h (FRAME_FIND_SAVED_REGS): Cleaned up a little to take
+ advantage of the new frame cache system.
+
+ * inferior.h, infrun.c, valops.c, valops.c, infcmd.c: Changed
+ mechanism to save inferior status over calls to inferior (eg.
+ call_function); implemented save_inferior_info and
+ restore_inferior_info.
+
+ * blockframe.c (get_prev_frame): Simplified this by a direct call
+ to get_prev_frame_info.
+
+ * frame.h, stack.c, printcmd.c, m-sparc.h, sparc-dep.c: Removed
+ all uses of frame_id_from_addr. There are short routines like it
+ still in frame_saved_pc (m-sparc.h) and parse_frame_spec
+ (stack.c). Eventually the one in frame_saved_pc will go away.
+
+ * infcmd.c, sparc-dep.c: Implemented a new mechanism for
+ re-selecting the selected frame on return from a call.
+
+ * blockframe.c, stack.c, findvar.c, printcmd.c, m-*.h: Changed
+ all routines and macros that took a "struct frame_info" as an
+ argument to take a "struct frame_info *". Routines: findarg,
+ framechain, print_frame_args, FRAME_ARGS_ADDRESS,
+ FRAME_STRUCT_ARGS_ADDRESS, FRAME_LOCALS_ADDRESS, FRAME_NUM_ARGS,
+ FRAME_FIND_SAVED_REGS.
+
+ * frame.h, stack.c, printcmd.c, infcmd.c, findvar.c, breakpoint.c,
+ blockframe.c, xgdb.c, i386-pinsn.c, gld-pinsn.c, m-umax.h,
+ m-sun2.h, m-sun3.h, m-sparc.h, m-pn.h, m-npl.h, m-news.h,
+ m-merlin.h, m-isi.h, m-i386.h, m-hp9k320.h: Changed routines to
+ use "struct frame_info *" internally.
+
+Wed Dec 7 12:07:54 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * frame.h, blockframe.c, m-sparc.h, sparc-dep.c: Changed all calls
+ to get_[prev_]frame_cache_item to get_[prev_]frame_info.
+
+ * blockframe.c: Elminated get_frame_cache_item and
+ get_prev_frame_cache_item; functionality now taken care of by
+ get_frame_info and get_prev_frame_info.
+
+ * blockframe.c: Put allocation on an obstack and eliminated fancy
+ reallocation routines, several variables, and various nasty
+ things.
+
+ * frame.h, stack.c, infrun.c, blockframe.c, sparc-dep.c: Changed
+ type FRAME to be a typedef to "struct frame_info *". Had to also
+ change routines that returned frame id's to return the pointer
+ instead of the cache index.
+
+ * infcmd.c (finish_command): Used proper method of getting from
+ function symbol to start of function. Was treating a symbol as a
+ value.
+
+ * blockframe.c, breakpoint.c, findvar.c, infcmd.c, stack.c,
+ xgdb.c, i386-pinsn.c, frame.h, m-hp9k320.h, m-i386.h, m-isi.h,
+ m-merlin.h, m-news.h, m-npl.h, m-pn.h, m-sparc.h, m-sun2.h,
+ m-sun3.h, m-umax.h: Changed get_frame_info and get_prev_frame_info
+ to return pointers instead of structures.
+
+ * blockframe.c (get_pc_function_start): Modified to go to misc
+ function table instead of bombing if pc was in a block without a
+ containing function.
+
+ * coffread.c: Dup'd descriptor passed to read_coff_symtab and
+ fdopen'd it so that there wouldn't be multiple closes on the same
+ fd. Also put (fclose, stream) on the cleanup list.
+
+ * printcmd.c, stack.c: Changed print_frame_args to take a
+ frame_info struct as argument instead of the address of the args
+ to the frame.
+
+ * m-i386.h (STORE_STRUCT_RETURN): Decremented sp by sizeof object
+ to store (an address) rather than 1.
+
+ * dbxread.c (read_dbx_symtab): Set first_object_file_end in
+ read_dbx_symtab (oops).
+
+ * coffread.c (fill_in_vptr_fieldno): Rewrote TYPE_BASECLASS as
+ necessary.
+
+Tue Dec 6 13:03:43 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * coffread.c: Added fake support for partial_symtabs to allow
+ compilation and execution without there use.
+ * inflow.c: Added a couple of minor USG mods.
+ * munch: Put in appropriate conditionals so that it would work on
+ USG systems.
+ * Makefile: Made regex.* handled same as obstack.*; made sure tar
+ file included everything I wanted it to include (including
+ malloc.c).
+
+ * dbxread.c (end_psymtab): Create an entry in the
+ partial_symtab_list for each subfile of the .o file just read in.
+ This allows a "list expread.y:10" to work when we haven't read in
+ expread.o's symbol stuff yet.
+
+ * symtab.h, dbxread.c (psymtab_to_symtab): Recognize pst->ldsymlen
+ == 0 as indicating a dummy psymtab, only in existence to cause the
+ dependency list to be read in.
+
+ * dbxread.c (sort_symtab_syms): Elminated reversal of symbols to
+ make sure that register debug symbol decls always come before
+ parameter symbols. After mod below, this is not needed.
+
+ * symtab.c (lookup_block_symbol): Take parameter type symbols
+ (LOC_ARG or LOC_REGPARM) after any other symbols which match.
+
+ * dbxread.c (read_type): When defining a type in terms of some
+ other type and the other type is supposed to have a pointer back
+ to this specific kind of type (pointer, reference, or function),
+ check to see if *that* type has been created yet. If it has, use
+ it and fill in the appropriate slot with a pointer to it.
+
+Mon Dec 5 11:25:04 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * symmisc.c: Eliminated existence of free_inclink_symtabs and
+ init_free_inclink_symtabs; they aren't called from anywhere, and
+ if they were they could disrupt gdb's data structure badly
+ (elimination of struct type's which values that stick around past
+ elimination of inclink symtabs).
+
+ * dbxread.c (symbol_file_command): Fixed a return pathway out of
+ the routine to do_cleanups before it left.
+
+ * infcmd.c (set_environment_command), gdb.texinfo: Added
+ capability to set environmental variable values to null.
+
+ * gdb.texinfo: Modified doc on "break" without args slightly.
+
+Sun Dec 4 17:03:16 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * dbxread.c (symbol_file_command): Added check; if there weren't
+ any debugging symbols in the file just read, the user is warned.
+
+ * infcmd.c: Commented set_environment_command (a little).
+
+ * createtags: Cleaned up and commented.
+
+ * Makefile: Updated depen_memory and write_inferior_memory in that errno is
+ checked after each ptrace and returned to the caller. Used in
+ value_at to detect references to addresses which are out of
+ bounds. Also core.c (xfer_core_file): return 1 if invalid
+ address, 0 otherwise.
+
+ * inflow.c, <machine>-infdep.c: removed all calls to ptrace from
+ inflo, m-sun3.h: Cleaned up dealings with
+ functions returning structu0 19:19:36 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * symmisc.c: (read_symsegs) Accept only format number 2. Since
+ the size of the type structure changed when C++ support was added,
+ format 1 can no longer be used.
+
+ * core.c, m-sunos4.h: (core_file_command) support for SunOS 4.0.
+ Slight change in the core structure. #ifdef SUNOS4. New file
+ m-sunos4.h. May want to change config.gdb also.
+
+Fri Jul 8 19:59:49 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * breakpoint.c: (break_command_1) Allow `break if condition'
+ rather than parsing `if' as a function name and returning an
+ error.
+
+Thu Jul 7 22:22:47 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * C++: valops.c, valprint.c, value.h, values.c: merged code to deal
+ with C++ expressions.
+
+Wed Jul 6 03:28:18 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * C++: dbxread.c: (read_dbx_symtab, condense_misc_bunches,
+ add_file_command) Merged code to read symbol information from
+ an incrementally linked file. symmisc.c:
+ (init_free_inclink_symtabs, free_inclink_symtabs) Cleanup
+ routines.
+
+Tue Jul 5 02:50:41 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * C++: symtab.c, breakpoint.c, source.c: Merged code to deal with
+ ambiguous line specifications. In C++ one can have overloaded
+ function names, so that `list classname::overloadedfuncname'
+ refers to several different lines, possibly sure currently configured machine
+ dependent files come first in e at corn-chex.ai.mit.edu)
+
+ * C++: symtab.c: replaced lookup_symtab_1 and lookup_symtab_2 with
+ a modified lookup_symbol which checks for fields of the current
+ implied argument `this'. printcmd.c, source.c, symtab.c,
+ valops.c: Need to change callers once callers are
+ installed.
+
+Wed Jun 29 01:26:56 1988 Peter TerMaat (pete at frosted-flakes.ai.mit.edu)
+
+ * C++: eval.c, expprint.c, expread.y, expression.h, valarith.c,
+ Merged code to deal with evaluation of user-defined operators,
+ member functions, and virtual functions.
+ binop_must_be_user_defined tests for user-defined binops,
+ value_x_binop calls the appropriate operator function.
+
+Tue Jun 28 02:56:42 1988 Peter TerMaat (pete at frosted-flakes.ai.mit.edu)
+
+ * C++: Makefile: changed the echo: expect 101 shift/reduce conflicts
+ and 1 reduce/reduce conflict.
+
+
+Local Variables:
+mode: indented-text
+eval: (auto-fill-mode 1)
+left-margin: 8
+fill-column: 74
+version-control: never
+End:
+
+ constructors, and flags being defined via public and via
+ virtual paths. Added fields NEXT_VARIANT, N_BASECLASSES,
+ and BASECLASSES to this type (tr: Changed types from
+ having to be derived from a single baseclass to a multiple
+ base class).
+ * symtab.h: Added macros to access new fields defined in symseg.h.
+ Added decl for lookup_basetype_type.
+ * dbxread.c
+ (condense_addl_misc_bunches): Function added to condense the misc
+ function bunches added by reading in a new .o file.
+ (read_addl_syms): Function added to read in symbols
+ from a new .o file (incremental linking).
+ (add_file_command): Command interface function to indicate
+ incrmental linking of a new .o file; this now calls
+ read_addl_syms and condense_addl_misc_bunches.
+ (define_symbol): Modified code to handle types defined from base
+ types which were not known when the derived class was
+ output.
+ (read_struct_type): Modified to better handle description of
+ struct types as derived types. Possibly derived from
+ several different base classes. Also added new code to
+ mark definitions via virtual paths or via public paths.
+ Killed seperate code to handle classes with destructors
+ but without constructors and improved marking of classes
+ as having destructors and constructors.
+ * infcmd.c: Modified call to val_print (one more argument).
+ * symtab.c (lookup_member_type): Modified to deal with new
+ structure in symseg.h.
+ (lookup_basetype_type): Function added to find or construct a type
+ ?derived? from the given type.
+ (decode_line_1): Modified to deal with new type data structures.
+ Modified to deal with new number of args for
+ decode_line_2.
+ (decode_line_2): Changed number of args (?why?).
+ (init_type): Added inits for new C++ fields from
+ symseg.h.
+ *valarith.c
+ (value_x_binop, value_binop): Added cases for BINOP_MIN &
+ BINOP_MAX.
+ * valops.c
+ (value_struct_elt, check_field, value_struct_elt_for_address):
+ Changed to deal with multiple possible baseclasses.
+ (value_of_this): Made SELECTED_FRAME an extern variable.
+ * valprint.c
+ (val_print): Added an argument DEREF_REF to dereference references
+ automatically, instead of printing them like pointers.
+ Changed number of arguments in recursive calls to itself.
+ Changed to deal with varibale numbers of base classes.
+ (value_print): Changed number of arguments to val_print. Print
+ type of value also if value is a reference.
+ (type_print_derivation_info): Added function to print out
+ derivation info a a type.
+ (type_print_base): Modified to use type_print_derivation_info and
+ to handle multiple baseclasses.
+
+Mon Nov 21 10:32:07 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * inflow.c (term_status_command): Add trailing newline to output.
+
+ * sparc-dep.c (do_save_insn, do_restore_insn): Saved
+ "stop_registers" over the call for the sake of normal_stop and
+ run_stack_dummy.
+
+ * m-sparc.h (EXTRACT_RETURN_VALUE): Put in parenthesis to force
+ addition of 8 to the int pointer, not the char pointer.
+
+ * sparc-pinsn.c (print_addr1): Believe that I have gotten the
+ syntax right for loads and stores as adb does it.
+
+ * symtab.c (list_symbols): Turned search for match on rexegp into
+ a single loop.
+
+ * dbxread.c (psymtab_to_symtab): Don't read it in if it's already
+ been read in.
+
+ * dbxread.c (psymtab_to_symtab): Changed error to fatal in
+ psymtab_to_symtab.
+
+ * expread.y (parse_number): Fixed bug which treated 'l' at end of
+ number as '0'.
+
+Fri Nov 18 13:57:33 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Was
+ being foolish and using pointers into an array I could realloc.
+ Converted these pointers into integers.
+
+Wed Nov 16 11:43:10 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * m-sparc.h (POP_FRAME): Made the new frame be PC_ADJUST of the
+ old frame.
+
+ * i386-pinsn.c, m-hp9k320.h, m-isi.h, m-merlin.h, m-news.h,
+ m-npl.h, m-pn.h, m-sparc.h, m-sun2.h, m-sun3.h, m-umax.h, m-vax.h:
+ Modified POP_FRAME to use the current frame instead of
+ read_register (FP_REGNUM) and to flush_cached_frames before
+ setting the current frame. Also added a call to set the current
+ frame in those POP_FRAMEs that didn't have it.
+
+ * infrun.c (wait_for_inferior): Moved call to set_current_frame up
+ to guarrantee that the current frame will always be set when a
+ POP_FRAME is done.
+
+ * infrun.c (normal_stop): Added something to reset the pc of the
+ current frame (was incorrect because of DECR_PC_AFTER_BREAK).
+
+ * valprint.c (val_print): Changed to check to see if a string was
+ out of bounds when being printed and to indicate this if so.
+
+ * convex-dep.c (read_inferior_memory): Changed to return the value
+ of errno if the call failed (which will be 0 if the call
+ suceeded).
+
+Tue Nov 15 10:17:15 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * infrun.c (wait_for_inferior): Two changes: 1) Added code to
+ not trigger the step breakpoint on recursive calls to functions
+ without frame info, and 2) Added calls to distinguish recursive
+ calls within a function without a frame (which next/nexti might
+ wish to step over) from jumps to the beginning of a function
+ (which it generally doesn't).
+
+ * m-sparc.h (INIT_EXTRA_FRAME_INFO): Bottom set correctly for leaf
+ parents.
+
+ * blockframe.c (get_prev_frame_cache_item): Put in mod to check
+ for a leaf node (by presence or lack of function prologue). If
+ there is a leaf node, it is assumed that SAVED_PC_AFTER_CALL is
+ valid. Otherwise, FRAME_SAVED_PC or read_pc is used.
+
+ * blockframe.c, frame.h: Did final deletion of unused routines and
+ commented problems with getting a pointer into the frame cache in
+ the frame_info structure comment.
+
+ * blockframe.c, frame.h, stack.c: Killed use of
+ frame_id_from_frame_info; used frame_id_from_addr instead.
+
+ * blockframe.c, frame.h, stack.c, others (oops): Combined stack
+ cache and frame info structures.
+
+ * blockframe.c, sparc-dep.c, stack.c: Created the function
+ create_new_frame and used it in place of bad calls to
+ frame_id_from_addr.
+
+ * blockframe.c, inflow.c, infrun.c, i386-pinsn.c, m-hp9k320.h,
+ m-npl.h, m-pn.h, m-sparc.h, m-sun3.h, m-vax.h, default-dep.c,
+ convex-dep.c, gould-dep.c, hp9k320-dep.c, news-dep.c, sparc-dep.c,
+ sun3-dep.c, umax-dep.c: Killed use of
+ set_current_Frame_by_address. Used set_current_frame
+ (create_new_frame...) instead.
+
+ * frame.h: Killed use of FRAME_FP_ID.
+
+ * infrun.c, blockframe.c: Killed select_frame_by_address. Used
+ select_frame (get_current_frame (), 0) (which was correct in all
+ cases that we need to worry about.
+
+Mon Nov 14 14:19:32 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * frame.h, blockframe.c, stack.c, m-sparc.h, sparc-dep.c: Added
+ mechanisms to deal with possible specification of frames
+ dyadically.
+
+Sun Nov 13 16:03:32 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
+
+ * ns32k-opcode.h: Add insns acbw, acbd.
+
+Sun Nov 13 15:09:58 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * breakpoint.c: Changed breakpoint structure to use the address of
+ a given frame (constant across inferior runs) as the criteria for
+ stopping instead of the frame ident (which varies across inferior
+ calls).
+
+Fri Nov 11 13:00:22 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * gld-pinsn.c (findframe): Modified to work with the new frame
+ id's. Actually, it looks as if this routine should be called with
+ an address anyway.
+
+ * findvar.c (find_saved_register): Altered bactrace loop to work
+ off of frames and not frame infos.
+
+ * frame.h, blockframe.c, stack.c, sparc-dep.c, m-sparc.h: Changed
+ FRAME from being the address of the frame to being a simple ident
+ which is an index into the frame_cache_item list.
+ * convex-dep.c, default-dep.c, gould-dep.c, hp9k320-dep.c,
+ i386-pinsn.c, inflow.c, infrun.c, news-dep.c, sparc-dep.c,
+ sun3-dep.c, umax-dep.c, m-hp9k320.h, m-npl.h, m-pn.h, m-sparc.h,
+ m-sun3.h, m-vax.h: Changed calls of the form set_current_frame
+ (read_register (FP_REGNUM)) to set_current_frame_by_address (...).
+
+Thu Nov 10 16:57:57 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * frame.h, blockframe.c, gld-pinsn.c, sparc-dep.c, stack.c,
+ infrun.c, findvar.c, m-sparc.h: Changed the FRAME type to be
+ purely an identifier, using FRAME_FP and FRAME_FP_ID to convert
+ back and forth between the two. The identifier is *currently*
+ still the frame pointer value for that frame.
+
+Wed Nov 9 17:28:14 1988 Chris Hanson (cph at kleph)
+
+ * m-hp9k320.h (FP_REGISTER_ADDR): Redefine this to return
+ difference between address of given FP register, and beginning of
+ `struct user' that it occurs in.
+
+ * hp9k320-dep.c (core_file_command): Fix sign error in size
+ argument to myread. Change buffer argument to pointer; was
+ copying entire structure.
+ (fetch_inferior_registers, store_inferior_registers): Replace
+ occurrences of `FP_REGISTER_ADDR_DIFF' with `FP_REGISTER_ADDR'.
+ Flush former definition.
+
+Wed Nov 9 12:11:37 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * xgdb.c: Killed include of initialize.h.
+
+ * Pulled in xgdb.c from the net.
+
+ * Checkpointed distribution (to provide to 3b2 guy).
+
+ * coffread.c, dbxread.c, symmisc.c, symtab.c, symseg.h: Changed
+ format of table of line number--pc mapping information. Can
+ handle negative pc's now.
+
+ * command.c: Deleted local copy of savestring; code in utils.c is
+ identical.
+
+Tue Nov 8 11:12:16 1988 Randall Smith (randy at plantaris.ai.mit.edu)
+
+ * gdb.texinfo: Added documentation for shell escape.
+
+Mon Nov 7 12:27:16 1988 Randall Smith (randy at sugar-bombs.ai.mit.edu)
+
+ * command.c: Added commands for shell escape.
+
+ * core.c, dbxread.c: Added ROBOTUSSIN mods.
+
+ * Checkpointed distribution.
+
+ * printcmd.c (x_command): Yanked error if there is no memory to
+ examine (could be looking at executable straight).
+
+ * sparc-pinsn.c (print_insn): Amount to leftshift sethi imm by is
+ now 10 (matches adb in output).
+
+ * printcmd.c (x_command): Don't attempt to set $_ & $__ if there
+ is no last_examine_value (can happen if you did an x/0).
+
+Fri Nov 4 13:44:49 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * printcmd.c (x_command): Error if there is no memory to examine.
+
+ * gdb.texinfo: Added "cont" to the command index.
+
+ * sparc-dep.c (do_save_insn): Fixed typo in shift amount.
+
+ * m68k-opcode.h: Fixed opcodes for 68881.
+
+ * breakpoint.c, infcmd.c, source.c: Changed defaults in several
+ places for decode_line_1 to work off of the default_breakpoint_*
+ values instead of current_source_* values (the current_source_*
+ values are off by 5 or so because of listing defaults).
+
+ * stack.c (frame_info): ifdef'd out FRAME_SPECIFCATION_DYADIC in
+ the stack.c module. If I can't do this right, I don't want to do
+ it at all. Read the comment there for more info.
+
+Mon Oct 31 16:23:06 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * gdb.texinfo: Added documentation on the "until" command.
+
+Sat Oct 29 17:47:10 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * breakpoint.c, infcmd.c: Added UNTIL_COMMAND and subroutines of
+ it.
+
+ * breakpoint.c, infcmd.c, infrun.c: Added new field to breakpoint
+ structure (silent, indicating a silent breakpoint), and modified
+ breakpoint_stop_status and things that read it's return value to
+ understand it.
+
+Fri Oct 28 17:45:33 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * dbxread.c, symmisc.c: Assorted speedups for readin, including
+ special casing most common symbols, and doing buffering instead of
+ calling malloc.
+
+Thu Oct 27 11:11:15 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * stack.c, sparc-dep.c, m-sparc.h: Modified to allow "info frame"
+ to take two arguments on the sparc and do the right thing with
+ them.
+
+ * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Put
+ stuff to put only symbols that didn't have debugging info on the
+ misc functions list back in.
+
+Wed Oct 26 10:10:32 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * valprint.c (type_print_varspec_suffix): Added check for
+ TYPE_LENGTH(TYPE_TARGET_TYPE(type)) > 0 to prevent divide by 0.
+
+ * printcmd.c (print_formatted): Added check for VALUE_REPEATED;
+ value_print needs to be called for that.
+
+ * infrun.c (wait_for_inferior): Added break when you decide to
+ stop on a null function prologue rather than continue stepping.
+
+ * m-sun3.h: Added explanatory comment to REGISTER_RAW_SIZE.
+
+ * expread.y (parse_c_1): Initialized paren_depth for each parse.
+
+Tue Oct 25 14:19:38 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * valprint.c, coffread.c, dbxread.c: Enum constant values in enum
+ type now accessed through TYPE_FIELD_BITPOS.
+
+ * dbxread.c (process_symbol_for_psymtab): Added code to deal with
+ possible lack of a ":" in a debugging symbol (do nothing).
+
+ * symtab.c (decode_line_1): Added check in case of all numbers for
+ complete lack of symbols.
+
+ * source.c (select_source_symtab): Made sure that this wouldn't
+ bomb on complete lack of symbols.
+
+Mon Oct 24 12:28:29 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * m-sparc.h, findvar.c: Ditched REGISTER_SAVED_UNIQUELY and based
+ code on REGISTER_IN_WINDOW_P and HAVE_REGISTER_WINDOWS. This will
+ break when we find a register window machine which saves the
+ window registers within the context of an inferior frame.
+
+ * sparc-dep.c (frame_saved_pc): Put PC_ADJUST return back in for
+ frame_saved_pc. Seems correct.
+
+ * findvar.c, m-sparc.h: Created the macro REGISTER_SAVED_UNIQUELY
+ to handle register window issues (ie. that find_saved_register
+ wasn't checking the selected frame itself for shit).
+
+ * sparc-dep.c (core_file_command): Offset target of o & g register
+ bcopy by 1 to hit correct registers.
+
+ * m-sparc.h: Changed STACK_END_ADDR.
+
+Sun Oct 23 19:41:51 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * sparc-dep.c (core_file_command): Added in code to get the i & l
+ registers from the stack in the corefile, and blew away some wrong
+ code to get i & l from inferior.
+
+Fri Oct 21 15:09:19 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
+
+ * m-sparc.h (PUSH_DUMMY_FRAME): Saved the value of the RP register
+ in the location reserved for i7 (in the created frame); this way
+ the rp value won't get lost. The pc (what we put into the rp in
+ this routine) gets saved seperately, so we loose no information.
+
+ * sparc-dep.c (do_save_insn & do_restore_insn): Added a wrapper to
+ preserve the proceed status state variables around each call to
+ proceed (the current frame was getting munged because this wasn't
+ being done).
+
+ * m-sparc.h (FRAME_FIND_SAVED_REGS): Fix bug: saved registers
+ addresses were being computed using absolute registers number,
+ rather than numbers relative to each group of regs.
+
+ * m-sparc.h (POP_FRAME): Fixed a bug (I hope) in the context
+ within which saved reg numbers were being interpetted. The
+ values to be restored were being gotten in the inferior frame, and
+ the restoring was done in the superior frame. This means that i
+ registers must be restored into o registers.
+
+ * sparc-dep.c (do_restore_insn): Modified to take a pc as an
+ argument, instead of a raw_buffer. This matches (at least it
+ appears to match) usage from POP_FRAME, which is the only place
+ from which do_restore_insn is called.
+
+ * sparc-dep.c (do_save_insn and do_restore_insn): Added comments.
+
+ * m-sparc.h (FRAME_FIND_SAVED_REGS): Modified my code to find the
+ save addresses of out registers to use the in regs off the stack
+ pointer when the current frame is 1 from the innermost.
+
+Thu Oct 20 13:56:15 1988 & Smith (randy at hobbes.ai.mit.edu)
+
+ * blockframe.c, m-sparc.h: Removed code associated with
+ GET_PREV_FRAME_FROM_CACHE_ITEM. This code was not needed for the
+ sparc; you can always find the previous frames fp from the fp of
+ the current frame (which is the sp of the previous). It's getting
+ the information associated with a given frame (ie. saved
+ registers) that's a bitch, because that stuff is saved relative to
+ the stack pointer rather than the frame pointer.
+
+ * m-sparc.h (GET_PREV_FRAME_FROM_CACHE_ITEM): Modified to return
+ the frame pointer of the previous frame instead of the stack
+ pointer of same.
+
+ * blockframe.c (flush_cached_frames): Modified call to
+ obstack_free to free back to frame_cache instead of back to zero.
+ This leaves the obstack control structure in finite state (and
+ still frees the entry allocated at frame_cache).
+
+Sat Oct 15 16:30:47 1988 & Smith (randy at tartarus.uchicago.edu)
+
+ * valops.c (call_function): Suicide material here. Fixed a typo;
+ CALL_DUMMY_STACK_ADJUST was spelled CAll_DUMMY_STACK_ADJUST on
+ line 530 of the file. This cost me three days. I'm giving up
+ typing for lent.
+
+Fri Oct 14 15:10:43 1988 & Smith (randy at tartarus.uchicago.edu)
+
+ * m-sparc.h: Corrected a minor mistake in the dummy frame code
+ that was getting the 5th argument and the first argument from the
+ same place.
+
+Tue Oct 11 11:49:33 1988 & Smith (randy at tartarus.uchicago.edu)
+
+ * infrun.c: Made stop_after_trap and stop_after_attach extern
+ instead of static so that code which used proceed from machine
+ dependent files could fiddle with them.
+
+ * blockframe.c, frame.h, sparc-dep.c, m-sparc.h: Changed sense of
+ ->prev and ->next in struct frame_cache_item to fit usage in rest
+ of gdb (oops).
+
+Mon Oct 10 15:32:42 1988 Randy Smith (randy at gargoyle.uchicago.edu)
+
+ * m-sparc.h, sparc-dep.c, blockframe.c, frame.h: Wrote
+ get_frame_cache_item. Modified FRAME_SAVED_PC and frame_saved_pc
+ to take only one argument and do the correct thing with it. Added
+ the two macros I recently defined in blockframe.c to m-sparc.h.
+ Have yet to compile this thing on a sparc, but I've now merged in
+ everything that I received from tiemann, either exactly, or simply
+ effectively.
+
+ * source.c: Added code to allocated space to sals.sals in the case
+ where no line was specified.
+
+ * blockframe.c, infrun.c: Modified to cache stack frames requested
+ to minimize accesses to subprocess.
+
+Tue Oct 4 15:10:39 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu)
+
+ * config.gdb: Added sparc.
+
+Mon Oct 3 23:01:22 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu)
+
+ * Makefile, blockframe.c, command.c, core.c, dbxread.c, defs.h,
+ expread.y, findvar.c, infcmd.c, inflow.c, infrun.c, sparc-pinsn.c,
+ m-sparc.h, sparc-def.c, printcmd.c, stack.c, symmisc.c, symseg.h,
+ valops.c, values.c: Did initial merge of sparc port. This will
+ not compile; have to do stack frame caching and finish port.
+
+ * inflow.c, gdb.texinfo: `tty' now resets the controling terminal.
+
+Fri Sep 30 11:31:16 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * inferior.h, infcmd.c, infrun.c: Changed the variable
+ stop_random_signal to stopped_by_random signal to fit in better
+ with name conventions (variable is not a direction to the
+ proceed/resume set; it is information from it).
+
+Thu Sep 29 13:30:46 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu)
+
+ * infcmd.c (finish_command): Value type of return value is now
+ whatever the function returns, not the type of the function (fixed
+ a bug in printing said value).
+
+ * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab):
+ Put *all* global symbols into misc_functions. This is what was
+ happening anyway, and we need it for find_pc_misc_function.
+
+ ** This was eventually taken out, but I didn't mark it in the
+ ChangeLog. Oops.
+
+ * dbxread.c (process_symbol_for_psymtab): Put every debugger
+ symbol which survives the top case except for constants on the
+ symchain. This means that all of these *won't* show up in misc
+ functions (this will be fixed once I make sure it's broken the way
+ it's supposed to be).
+
+ * dbxread.c: Modified placement of debugger globals onto the hash
+ list; now we exclude the stuff after the colon and don't skip the
+ first character (debugger symbols don't have underscores).
+
+ * dbxread.c: Killed debuginfo stuff with ifdef's.
+
+Wed Sep 28 14:31:51 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu)
+
+ * symtab.h, dbxread.c: Modified to deal with BINCL, EINCL, and
+ EXCL symbols produced by the sun loader by adding a list of
+ pre-requisite partial_symtabs that each partial symtab needs.
+
+ * symtab.h, dbxread.c, symtab.c, symmisc.c: Modified to avoid
+ doing a qsort on the local (static) psymbols for each file to
+ speed startup. This feature is not completely debugged, but it's
+ inclusion has forced the inclusion of another feature (dealing
+ with EINCL's, BINCL's and EXCL's) and so I'm going to go in and
+ deal with them.
+
+ * dbxread.c (process_symbol_for_psymtab): Made sure that the class
+ of the symbol made it into the partial_symbol entry.
+
+Tue Sep 27 15:10:26 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * dbxread.c: Fixed bug; init_psymbol_list was not being called
+ with the right number of arguments (1).
+
+ * dbxread.c: Put ifdef's around N_MAIN, N_M2C, and N_SCOPE to
+ allow compilation on a microvax.
+
+ * config.gdb: Modified so that "config.gdb vax" would work.
+
+ * dbxread.c, symtab.h, symmisc.h, symtab.c, source.c: Put in many
+ and varied hacks to speed up gdb startup including: A complete
+ rewrite of read_dbx_symtab, a modification of the partial_symtab
+ data type, deletion of select_source_symtab from
+ symbol_file_command, and optimiztion of the call to strcmp in
+ compare_psymbols.
+
+Thu Sep 22 11:08:54 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * dbxread.c (psymtab_to_symtab): Removed call to
+ init_misc_functions.
+
+ * dbxread.c: Fixed enumeration type clash (used enum instead of
+ integer constant).
+
+ * breakpoint.c: Fixed typo; lack of \ at end of line in middle of
+ string constant.
+
+ * symseg.h: Fixed typo; lack of semicolon after structure
+ definition.
+
+ * command.c, breakpoint.c, printcmd.c: Added cmdlist editing
+ functions to add commands with the abbrev flag set. Changed
+ help_cmd_list to recognize this flag and modified unset,
+ undisplay, and enable, disable, and delete breakpoints to have
+ this flag set.
+
+Wed Sep 21 13:34:19 1988 Randall Smith (randy at plantaris.ai.mit.edu)
+
+ * breakpoint.c, infcmd.c, gdb.texinfo: Created "unset" as an alias
+ for delete, and changed "unset-environment" to be the
+ "environment" subcommand of "delete".
+
+ * gdb.texinfo, valprint.c: Added documentation in the manual for
+ breaking the set-* commands into subcommands of set. Changed "set
+ maximum" to "set array-max".
+
+ * main.c, printcmd.c, breakpoint.c: Moved the declaration of
+ command lists into main and setup a function in main initializing
+ them to guarrantee that they would be initialized before calling
+ any of the individual files initialize routines.
+
+ * command.c (lookup_cmd): A null string subcommand is treated as
+ an unknown subcommand rather than an ambiguous one (eg. "set $x =
+ 1" will now work).
+
+ * infrun.c (wait_for_inferior): Put in ifdef for Sony News in
+ check for trap by INNER_THAN macro.
+
+ * eval.c (evaluate_subexp): Put in catch to keep the user from
+ attempting to call a non function as a function.
+
+Tue Sep 20 10:35:53 1988 Randall Smith (randy at oatmeal.ai.mit.edu)
+
+ * dbxread.c (read_dbx_symtab): Installed code to keep track of
+ which global symbols did not have debugger symbols refering to
+ them, and recording these via record_misc_function.
+
+ * dbxread.c: Killed code to check for extra global symbols in the
+ debugger symbol table.
+
+ * printcmd.c, breakpoint.c: Modified help entries for several
+ commands to make sure that abbreviations were clearly marked and
+ that the right commands showed up in the help listings.
+
+ * main.c, command.c, breakpoint.c, infcmd.c, printcmd.c,
+ valprint.c, defs.h: Modified help system to allow help on a class
+ name to show subcommands as well as commands and help on a command
+ to show *all* subcommands of that command.
+
+Fri Sep 16 16:51:19 1988 Randall Smith (randy at gluteus.ai.mit.edu)
+
+ * breakpoint.c (_initialize_breakpoint): Made "breakpoints"
+ subcommands of enable, disable, and delete use class 0 (ie. they
+ show up when you do a help xxx now).
+
+ * infcmd.c,printcmd,c,main.c,valprint.c: Changed the set-*
+ commands into subcommands of set. Created "set variable" for use
+ with variables whose names might conflict with other subcommands.
+
+ * blockframe.c, dbxread.c, coffread.c, expread.y, source.c:
+ Fixed mostly minor (and one major one in block_for_pc) bugs
+ involving checking the partial_symtab_list when a scan through the
+ symtab_list fails.
+
+Wed Sep 14 12:02:05 1988 Randall Smith (randy at sugar-smacks.ai.mit.edu)
+
+ * breakpoint.c, gdb.texinfo: Added enable breakpoints, disable
+ breakpoints and delete breakpoints as synonyms for enable,
+ disable, and delete. This seemed reasonable because of the
+ immeninent arrival of watchpoints & etc.
+
+ * gdb.texinfo: Added enable display, disable display, and delete
+ display to manual.
+
+Tue Sep 13 16:53:56 1988 Randall Smith (randy at sugar-smacks.ai.mit.edu)
+
+ * inferior.h, infrun.c, infcmd.c: Added variable
+ stop_random_signal to indicate when a proceed had been stopped by
+ an unexpected signal. Used this to determine (in normal_stop)
+ whether the current display point should be deleted.
+
+ * valops.c: Fix to value_ind to check for reference before doing a
+ COERCE_ARRAY.
+
+Sun Jul 31 11:42:36 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu)
+
+ * breakpoint.c (_initialize_breakpoint): Clean up doc for commands
+ that can now apply also to auto-displays.
+
+ * coffread.c (record_line): Corrected a spazz in editing.
+ Also removed the two lines that assume line-numbers appear
+ only in increasing order.
+
+Tue Jul 26 22:19:06 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * expression.h, eval.c, expprint.c, printcmd.c, valarith.c,
+ valops.c, valprint.c, values.c, m-*.h: Changes for evaluating and
+ displaying 64-bit `long long' integers. Each machine must define
+ a LONGEST type, and a BUILTIN_TYPE_LONGEST.
+
+ * symmisc.c: (print_symtab) check the status of the fopen and call
+ perror_with_name if needed.
+
+Thu Jul 21 00:56:11 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * Convex: core.c: changes required by Convex's SOFF format were
+ isolated in convex-dep.c.
+
+Wed Jul 20 21:26:10 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * coffread.c, core.c, expread.y, i386-pinsn.c, infcmd.c, inflow.c,
+ infrun.c, m-i386.h, main.c, remote.c, source.c, valops.c:
+ Improvements for the handling of the i386 and other machines
+ running USG. (Several of these files just needed extra header files
+ such as types.h.) utils.c: added bcopy, bcmp, bzero, getwd, list
+ of signals, and queue routines for USG systems. Added vfork macro
+ to i386
+
+ * printcmd.c, breakpoint.c: New commands to enable/disable
+ auto-displays. Also `delete display displaynumber' works like
+ `undisplay displaynumber'.
+
+Tue Jul 19 02:17:18 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * coffread.c: (coff_lookup_type) Wrong portion of type_vector was
+ being bzero'd after type_vector was reallocated.
+
+ * printcmd.c: (delete_display) Check for a display chain before
+ attempting to delete a display.
+
+ * core.c, *-dep.c (*-infdep moved to *-dep): machine-dependent
+ parts of core.c (core_file_command, exec_file_command) moved to
+ *-dep.c.
+
+Mon Jul 18 19:45:51 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * dbxread.c: typo in read_struct_type (missing '=') was causing a
+ C struct to be parsed as a C++ struct, resulting in a `invalid
+ character' message.
+
+Sun Jul 17 22:27:32 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * printcmd.c, symtab.c, valops.c, expread.y: When an expression is
+ read, the innermost block required to evaluate the expression is
+ saved in the global variable `innermost_block'. This information
+ is saved in the `block' field of an auto-display so that
+ expressions with inactive variables can be skipped. `info display'
+ tells the user which displays are active and which are not. New
+ fn `contained_in' returns nonzero if one block is contained within
+ another.
+
+Fri Jul 15 01:53:14 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * infrun.c, m-i386.h: Use macro TRAPS_EXPECTED to set number of
+ traps to skip when sh execs the program. Default is 2, m-i386.h
+ overrides this and sets to 4.
+
+ * coffread.c, infrun.c: minor changes for the i386. May be able
+ to eliminate them with more general code.
+
+ * default-infdep.c: #ifdef SYSTEMV, include header file types.h.
+ Also switched the order of signal.h and user.h, since System 5
+ requires signal.h to come first.
+
+ * core.c main.c, remote,c, source.c, inflow.c: #ifdef SYSTEMV,
+ include various header files. Usually types.h and fcntl.h.
+
+ * utils.c: added queue routines needed by the i386 (and other sys
+ 5 machines).
+
+ * sys5.c, regex.c, regex.h: new files for sys 5 systems. (The
+ regex files are simply links to /gp/gnu/lib.)
+
+Thu Jul 14 01:47:14 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * config.gdb, README: Provide a list of known machines when user
+ enters an invalid machine. New second arg is operating system,
+ currently only used with `sunos4' or `os4'. Entry for i386 added.
+
+ * news-infdep.c: new file.
+
+ * m-news.h: new version which deals with new bugs in news800's OS.
+
+Tue Jul 12 19:52:16 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * Makefile, *.c, munch, config.gdb, README: New initialization
+ scheme uses nm to find functions whose names begin with
+ `_initialize_'. Files `initialize.h', `firstfile.c',
+ `lastfile.c', `m-*init.h' no longer needed.
+
+ * eval.c, symtab.c, valarith.c, valops.c, value.h, values.c: Bug
+ fixes from gdb+ 2.5.4. evaluate_subexp takes a new arg, type
+ expected. New fn value_virtual_fn_field.
+
+Mon Jul 11 00:48:49 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * core.c (read_memory): xfer_core_file was being called with an
+ extra argument (0) by read_memory.
+
+ * core.c (read_memory), *-infdep.c (read_inferior_memory),
+ valops.c (value_at): read_memory and read_inferior_memory now work
+ like write_memory and write_inferior_memory in that errno is
+ checked after each ptrace and returned to the caller. Used in
+ value_at to detect references to addresses which are out of
+ bounds. Also core.c (xfer_core_file): return 1 if invalid
+ address, 0 otherwise.
+
+ * inflow.c, <machine>-infdep.c: removed all calls to ptrace from
+ inflow.c and put them in machine-dependent files *-infdep.c.
+
+Sun Jul 10 19:19:36 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * symmisc.c: (read_symsegs) Accept only format number 2. Since
+ the size of the type structure changed when C++ support was added,
+ format 1 can no longer be used.
+
+ * core.c, m-sunos4.h: (core_file_command) support for SunOS 4.0.
+ Slight change in the core structure. #ifdef SUNOS4. New file
+ m-sunos4.h. May want to change config.gdb also.
+
+Fri Jul 8 19:59:49 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * breakpoint.c: (break_command_1) Allow `break if condition'
+ rather than parsing `if' as a function name and returning an
+ error.
+
+Thu Jul 7 22:22:47 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * C++: valops.c, valprint.c, value.h, values.c: merged code to deal
+ with C++ expressions.
+
+Wed Jul 6 03:28:18 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * C++: dbxread.c: (read_dbx_symtab, condense_misc_bunches,
+ add_file_command) Merged code to read symbol information from
+ an incrementally linked file. symmisc.c:
+ (init_free_inclink_symtabs, free_inclink_symtabs) Cleanup
+ routines.
+
+Tue Jul 5 02:50:41 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * C++: symtab.c, breakpoint.c, source.c: Merged code to deal with
+ ambiguous line specifications. In C++ one can have overloaded
+ function names, so that `list classname::overloadedfuncname'
+ refers to several different lines, possibly in different files.
+
+Fri Jul 1 02:44:20 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu)
+
+ * C++: symtab.c: replaced lookup_symtab_1 and lookup_symtab_2 with
+ a modified lookup_symbol which checks for fields of the current
+ implied argument `this'. printcmd.c, source.c, symtab.c,
+ valops.c: Need to change callers once callers are
+ installed.
+
+Wed Jun 29 01:26:56 1988 Peter TerMaat (pete at frosted-flakes.ai.mit.edu)
+
+ * C++: eval.c, expprint.c, expread.y, expression.h, valarith.c,
+ Merged code to deal with evaluation of user-defined operators,
+ member functions, and virtual functions.
+ binop_must_be_user_defined tests for user-defined binops,
+ value_x_binop calls the appropriate operator function.
+
+Tue Jun 28 02:56:42 1988 Peter TerMaat (pete at frosted-flakes.ai.mit.edu)
+
+ * C++: Makefile: changed the echo: expect 101 shift/reduce conflicts
+ and 1 reduce/reduce conflict.
+
+Local Variables:
+mode: indented-text
+left-margin: 8
+fill-column: 74
+version-control: never
+End:
diff --git a/gnu/usr.bin/gdb/Gdbinit b/gnu/usr.bin/gdb/Gdbinit
new file mode 100644
index 0000000..bcacd5d
--- /dev/null
+++ b/gnu/usr.bin/gdb/Gdbinit
@@ -0,0 +1,15 @@
+echo Setting up the environment for debugging gdb.\n
+
+b fatal
+
+b info_command
+commands
+ silent
+ return
+end
+
+define rr
+ run
+end
+
+set prompt (top-gdb)
diff --git a/gnu/usr.bin/gdb/Makefile b/gnu/usr.bin/gdb/Makefile
new file mode 100644
index 0000000..8536444
--- /dev/null
+++ b/gnu/usr.bin/gdb/Makefile
@@ -0,0 +1,3 @@
+SUBDIR= bfd libiberty mmalloc gdb
+
+.include <bsd.subdir.mk>
diff --git a/gnu/usr.bin/gdb/Makefile.dist b/gnu/usr.bin/gdb/Makefile.dist
new file mode 100644
index 0000000..3cbc91f
--- /dev/null
+++ b/gnu/usr.bin/gdb/Makefile.dist
@@ -0,0 +1,371 @@
+/* This file should be run through the C preprocessor by config.gdb
+ to produce the Makefile. */
+
+/* Define this to xgdb if you want to compile xgdb as well as gdb. */
+XGDB=
+/* Place to install binaries. */
+bindir=/usr/local/bin
+/* Place to install X binaries. */
+xbindir=$(bindir)
+
+/* System V: If you compile gdb with a compiler which uses the coff
+ encapsulation feature (this is a function of the compiler used, NOT
+ of the m-?.h file selected by config.gdb), you must make sure that
+ the GNU nm is the one that is used by munch. */
+
+/* If you are compiling with GCC, make sure that either 1) You use the
+ -traditional flag, or 2) You have the fixed include files where GCC
+ can reach them. Otherwise the ioctl calls in inflow.c and readline.c
+ will be incorrectly compiled. The "fixincludes" script in the gcc
+ distribution will fix your include files up. */
+/* CC=gcc -traditional */
+CC=cc
+
+/* It is also possible that you will need to add -I/usr/include/sys to the
+ CFLAGS section if your system doesn't have fcntl.h in /usr/include (which
+ is where it should be according to Posix). */
+
+YACC=bison -y -v
+/* YACC=yacc */
+SHELL=/bin/sh
+MAKE=make
+
+/* Set this up with gcc if you have gnu ld and the loader will print out
+ line numbers for undefinded refs. */
+/* CC-LD=gcc -static */
+CC-LD=${CC}
+
+/* If you are using the GNU C library, uncomment the following line. */
+/* HAVE_VPRINTF_DEFINE = -DHAVE_VPRINTF */
+
+/* -I. for "#include <obstack.h>". Possibly regex.h also. */
+
+/* M_CFLAGS, if defined, has system-dependent CFLAGS. */
+#if !defined(M_CFLAGS)
+#define M_CFLAGS
+#endif
+
+/* CFLAGS for both GDB and readline. */
+GLOBAL_CFLAGS = -g M_CFLAGS
+CFLAGS = -I. ${HAVE_VPRINTF_DEFINE} ${GLOBAL_CFLAGS}
+/* None of the things in CFLAGS will do any harm, and on some systems
+ (e.g. SunOS4) it is important to use the M_CFLAGS. */
+LDFLAGS = $(CFLAGS)
+
+/*
+ define this to be "obstack.o" if you don't have the obstack library installed
+ you must at the same time define OBSTACK1 as "obstack.o"
+ so that the dependencies work right. Similarly with REGEX and "regex.o".
+ You must define REGEX and REGEX1 on USG machines.
+ If your sysyem is missing alloca(), or, more likely, it's there but
+ it doesn't work, define ALLOCA & ALLOCA1 */
+OBSTACK = obstack.o
+OBSTACK1 = obstack.o
+
+#ifdef M_REGEX
+REGEX = M_REGEX
+REGEX1 = M_REGEX
+#else
+REGEX =
+REGEX1 =
+#endif
+
+#ifdef M_ALLOCA
+ALLOCA = M_ALLOCA
+ALLOCA1 = M_ALLOCA
+#else
+ALLOCA =
+ALLOCA1 =
+#endif
+
+/*
+ define this to be "malloc.o" if you want to use the gnu malloc routine
+ (useful for debugging memory allocation problems in gdb). Otherwise, leave
+ it blank. */
+/* GNU_MALLOC = */
+GNU_MALLOC = malloc.o
+
+/* Flags to be used in compiling malloc.o
+ Specify range checking for storage allocation. */
+/* MALLOC_FLAGS = ${CFLAGS} */
+MALLOC_FLAGS = ${CFLAGS} -Drcheck -Dbotch=fatal_dump_core -DMSTATS
+
+/* Define SYSV if compiling on a system V or HP machine. */
+#ifdef M_SYSV
+SYSV_DEFINE = -DSYSV
+#else
+SYSV_DEFINE =
+#endif
+
+/* MUNCH_DEFINE should be -DSYSV if have System V-style nm,
+ or null if have BSD-style nm. */
+#ifdef M_BSD_NM
+MUNCH_DEFINE =
+#else
+MUNCH_DEFINE = ${SYSV_DEFINE}
+#endif
+
+/* Flags that describe where you can find the termcap library.
+ You may need to make other arrangements for USG. */
+TERMCAP = -ltermcap
+
+/* M_CLIBS, if defined, has system-dependent libs
+ For example, -lPW for System V to get alloca(). */
+#ifndef M_CLIBS
+#define M_CLIBS
+#endif
+CLIBS = ${ADD_FILES} ${TERMCAP} M_CLIBS
+
+ADD_FILES = ${OBSTACK} ${REGEX} ${ALLOCA} ${GNU_MALLOC}
+ADD_DEPS = ${OBSTACK1} ${REGEX1} ${ALLOCA1} ${GNU_MALLOC}
+
+SFILES = blockframe.c breakpoint.c dbxread.c coffread.c command.c core.c \
+ environ.c eval.c expprint.c findvar.c infcmd.c inflow.c infrun.c \
+ kdb-start.c main.c printcmd.c \
+ remote.c source.c stack.c standalone.c stuff.c symmisc.c symtab.c \
+ utils.c valarith.c valops.c valprint.c values.c version.c expread.y \
+ xgdb.c
+
+DEPFILES = umax-dep.c gould-dep.c default-dep.c sun3-dep.c \
+ sparc-dep.c hp9k320-dep.c hp300bsd-dep.c news-dep.c i386-dep.c \
+ symmetry-dep.c convex-dep.c altos-dep.c isi-dep.c pyr-dep.c
+
+PINSNS = gld-pinsn.c i386-pinsn.c sparc-pinsn.c vax-pinsn.c m68k-pinsn.c \
+ ns32k-pinsn.c convex-pinsn.c pyr-pinsn.c
+
+HFILES = command.h defs.h environ.h expression.h frame.h getpagesize.h \
+ inferior.h symseg.h symtab.h value.h wait.h \
+ a.out.encap.h a.out.gnu.h stab.gnu.h
+
+OPCODES = m68k-opcode.h pn-opcode.h sparc-opcode.h npl-opcode.h vax-opcode.h \
+ ns32k-opcode.h convex-opcode.h pyr-opcode.h
+
+MFILES = m-hp9k320.h m-hp300bsd.h m-i386.h m-i386gas.h \
+ m-i386-sv32.h m-i386g-sv32.h m-isi.h m-merlin.h \
+ m-altos.h m-news.h m-newsos3.h m-npl.h m-pn.h \
+ m-sparc.h m-sun2.h m-sun3.h m-sun2os4.h \
+ m-sun3os4.h m-sun4os4.h m-umax.h m-vax.h m-symmetry.h m-convex.h \
+ m-pyr.h
+
+/* This list of files really shouldn't be in this makefile, but I can't think
+ of any good way to get the readline makefile to tell us what files
+ to put in our tarfile. */
+READLINE = readline.c history.c funmap.c \
+ emacs_keymap.c vi_keymap.c vi_mode.c keymaps.c \
+ readline.h history.h keymaps.h chardefs.h \
+ inc-readline.texinfo inc-history.texinfo \
+ readline.texinfo history.texinfo \
+ Makefile ChangeLog
+
+REMOTE_EXAMPLES = remote-sa.m68k.shar remote-multi.shar
+
+POSSLIBS = obstack.h obstack.c regex.c regex.h malloc.c alloca.c
+
+TESTS = testbpt.c testfun.c testrec.c testreg.c testregs.c
+
+OTHERS = Makefile.dist createtags munch config.gdb ChangeLog README TAGS \
+ gdb.texinfo .gdbinit COPYING expread.tab.c stab.def \
+ XGDB-README copying.c Projects Convex.notes copying.awk hp-include
+
+TAGFILES = ${SFILES} ${DEPFILES} ${PINSNS} ${HFILES} ${OPCODES} ${MFILES} \
+ ${POSSLIBS}
+TARFILES = ${TAGFILES} ${OTHERS} ${REMOTE_EXAMPLES}
+
+OBS = main.o blockframe.o breakpoint.o findvar.o stack.o source.o \
+ values.o eval.o valops.o valarith.o valprint.o printcmd.o \
+ symtab.o symmisc.o coffread.o dbxread.o infcmd.o infrun.o remote.o \
+ command.o utils.o expread.o expprint.o pinsn.o environ.o version.o \
+ copying.o ${READLINEOBS}
+
+TSOBS = core.o inflow.o dep.o
+
+NTSOBS = standalone.o
+
+TSSTART = /lib/crt0.o
+
+NTSSTART = kdb-start.o
+
+RL_LIB = readline/libreadline.a
+
+/* Do some fancy trickery to produce a line like
+ -DM_MAKEDEFINE="-DM_SYSV -DM_BSD_NM".
+*/
+MD=M_MAKEDEFINE
+
+/* Avoid funny things that Sun's make throws in for us. */
+/* TARGET_ARCH is supposed to get around it putting in the machine type.
+ If the "things" up there really is plural, we'll need to do something
+ else as well. */
+/*.c.o:
+ ${CC} -c ${CFLAGS} $< */
+TARGET_ARCH=
+
+all: gdb $(XGDB)
+
+install: gdb $(XGDB)
+ cp gdb $(bindir)/gdb.new
+ mv $(bindir)/gdb.new $(bindir)/gdb
+ -if [ "$(XGDB)" = xgdb ]; then \
+ cp xgdb $(xbindir)/xgdb.new; \
+ mv $(xbindir)/xgdb.new $(xbindir)xgdb; \
+ fi
+
+gdb : $(OBS) $(TSOBS) ${ADD_DEPS} ${RL_LIB}
+ rm -f init.c
+ ./munch ${MUNCH_DEFINE} $(OBS) $(TSOBS) > init.c
+ ${CC-LD} $(LDFLAGS) -o gdb init.c $(OBS) $(TSOBS) ${RL_LIB} $(CLIBS)
+
+/* This is useful when debugging GDB, because Unix doesn't let you run GDB
+ on itself without copying the executable. So "make gdb1" will make
+ gdb and put a copy in gdb1, and you can run it with "gdb gdb1". */
+gdb1 : gdb
+ cp gdb gdb1
+
+Makefile : Makefile.dist
+ cp Makefile.dist tmp.c
+ $(CC) -E >Makefile tmp.c $(MD) "-DM_MAKEDEFINE=$(MD)"
+ -rm tmp.c
+/* This did not work-- -Usparc became "-Usparc" became "-Usparc.
+ Or something like that. */
+/* $(CC) -E >Makefile tmp.c $(MD) "-DM_MAKEDEFINE=\"$(MD)\"" */
+
+xgdb : $(OBS) $(TSOBS) xgdb.o ${ADD_DEPS} ${RL_LIB}
+ rm -f init.c
+ ./munch ${MUNCH_DEFINE} $(OBS) $(TSOBS) xgdb.o > init.c
+ $(CC-LD) $(LDFLAGS) -o xgdb init.c $(OBS) $(TSOBS) xgdb.o \
+ -lXaw -lXmu -lXt -lX11 ${RL_LIB} $(CLIBS)
+
+/* Old (pre R3) xgdb comp.
+ $(CC-LD) $(LDFLAGS) -o xgdb init.c $(OBS) $(TSOBS) xgdb.o \
+ -lXaw -lXt -lX11 $(CLIBS) */
+
+kdb : $(NTSSTART) $(OBS) $(NTSOBS) ${ADD_DEPS} ${RL_LIB}
+ rm -f init.c
+ ./munch ${MUNCH_DEFINE} $(OBS) $(NTSOBS) > init.c
+ $(CC) $(LDFLAGS) -c init.c $(CLIBS)
+ ld -o kdb $(NTSSTART) $(OBS) $(NTSOBS) init.o ${RL_LIB} -lc $(CLIBS)
+
+/* If it can figure out the appropriate order, createtags will make sure
+ that the proper m-*, *-dep, *-pinsn, and *-opcode files come first
+ in the tags list. It will attempt to do the same for dbxread.c and
+ coffread.c. This makes using M-. on machine dependent routines much
+ easier. */
+
+TAGS: ${TAGFILES}
+ createtags ${TAGFILES}
+tags: TAGS
+
+gdb.tar: ${TARFILES}
+ rm -f gdb.tar
+ mkdir dist-gdb
+ cd dist-gdb ; for i in ${TARFILES} ; do ln -s ../$$i . ; done
+ mkdir dist-gdb/readline
+ cd dist-gdb/readline ; for i in ${READLINE} ; do ln -s ../../readline/$$i . ; done
+ tar chf gdb.tar dist-gdb
+ rm -rf dist-gdb
+
+/* Remove gdb.tar.Z so stupid compress doesn't ask whether we want to
+ overwrite it. compress -f is not what we want, because we do want
+ to know if compress would not make it smaller. */
+gdb.tar.Z: gdb.tar
+ if [ -f gdb.tar.Z ]; then rm -f gdb.tar.Z; else true; fi
+ compress gdb.tar
+
+clean:
+ rm -f ${OBS} ${TSOBS} ${NTSOBS} ${OBSTACK} ${REGEX} ${GNU_MALLOC}
+ rm -f init.c init.o
+ rm -f xgdb.o xgdb
+ rm -f gdb core gdb.tar gdb.tar.Z make.log
+ rm -f gdb[0-9]
+ cd readline ; make clean
+
+distclean: clean expread.tab.c TAGS
+ rm -f dep.c opcode.h param.h pinsn.c config.status
+ rm -f y.output yacc.acts yacc.tmp
+ rm -f ${TESTS} Makefile
+
+realclean: clean
+ rm -f expread.tab.c TAGS
+ rm -f dep.c opcode.h param.h pinsn.c config.status
+ rm -f Makefile
+
+xgdb.o : defs.h param.h symtab.h frame.h
+
+/* Make copying.c from COPYING */
+copying.c : COPYING copying.awk
+ awk -f copying.awk < COPYING > copying.c
+
+expread.tab.c : expread.y
+ @echo 'Expect 4 shift/reduce conflict.'
+ ${YACC} expread.y
+ mv y.tab.c expread.tab.c
+
+expread.o : expread.tab.c defs.h param.h symtab.h frame.h expression.h
+ $(CC) -c ${CFLAGS} expread.tab.c
+ mv expread.tab.o expread.o
+
+readline/libreadline.a : force_update
+ cd readline ; ${MAKE} "SYSV=${SYSV_DEFINE}" \
+ "DEBUG_FLAGS=${GLOBAL_CFLAGS}" "CC=${CC}" libreadline.a
+
+force_update :
+
+/* Only useful if you are using the gnu malloc routines. */
+malloc.o : malloc.c
+ ${CC} -c ${MALLOC_FLAGS} malloc.c
+
+/* dep.o depends on config.status in case someone reconfigures gdb out
+ from under an already compiled gdb. */
+dep.o : dep.c config.status defs.h param.h frame.h inferior.h obstack.h \
+ a.out.encap.h
+
+/* pinsn.o depends on config.status in case someone reconfigures gdb out
+ from under an already compiled gdb. */
+pinsn.o : pinsn.c config.status defs.h param.h symtab.h obstack.h symseg.h \
+ frame.h opcode.h
+
+/* The rest of this is a standard dependencies list (hand edited output of
+ cpp -M). It does not include dependencies of .o files on .c files. */
+/* All files which depend on config.status also depend on param.h in case
+ someone reconfigures gdb out from under an already compiled gdb. */
+blockframe.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h
+breakpoint.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h
+coffread.o : defs.h param.h config.status
+command.o : command.h defs.h
+core.o : defs.h param.h config.status a.out.encap.h
+dbxread.o : param.h config.status defs.h symtab.h obstack.h symseg.h a.out.encap.h \
+ stab.gnu.h
+environ.o : environ.h
+eval.o : defs.h param.h config.status symtab.h obstack.h symseg.h value.h expression.h
+expprint.o : defs.h symtab.h obstack.h symseg.h param.h config.status expression.h
+findvar.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h value.h
+infcmd.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h inferior.h \
+ environ.h value.h
+inflow.o : defs.h param.h config.status frame.h inferior.h
+infrun.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h inferior.h \
+ wait.h
+kdb-start.o : defs.h param.h config.status
+main.o : defs.h command.h param.h config.status
+malloc.o : getpagesize.h
+obstack.o : obstack.h
+printcmd.o : defs.h param.h config.status frame.h symtab.h obstack.h symseg.h value.h \
+ expression.h
+regex.o : regex.h
+remote.o : defs.h param.h config.status frame.h inferior.h wait.h
+source.o : defs.h symtab.h obstack.h symseg.h param.h config.status
+stack.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h
+standalone.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h \
+ inferior.h wait.h
+symmisc.o : defs.h symtab.h obstack.h symseg.h obstack.h
+symtab.o : defs.h symtab.h obstack.h symseg.h param.h config.status obstack.h
+utils.o : defs.h param.h config.status
+valarith.o : defs.h param.h config.status symtab.h obstack.h symseg.h value.h expression.h
+valops.o : defs.h param.h config.status symtab.h obstack.h symseg.h value.h frame.h \
+ inferior.h
+valprint.o : defs.h param.h config.status symtab.h obstack.h symseg.h value.h
+values.o : defs.h param.h config.status symtab.h obstack.h symseg.h value.h
+
+robotussin.h : getpagesize.h
+symtab.h : obstack.h symseg.h
+a.out.encap.h : a.out.gnu.h
+
diff --git a/gnu/usr.bin/gdb/Projects b/gnu/usr.bin/gdb/Projects
new file mode 100644
index 0000000..f38f6c7
--- /dev/null
+++ b/gnu/usr.bin/gdb/Projects
@@ -0,0 +1,114 @@
+
+ Suggested projects for aspiring or current GDB hackers
+ ======================================================
+
+ (You should probably chat with kingdon@ai.mit.edu to make sure that
+ no one else is doing the project you chose).
+
+Add watchpoints (break if a memory location changes). This would
+usually have to involve constant single stepping, but occasionally
+there is operating system support which gdb should be able to cleanly
+use (e.g. on the 80386, there are 4 debug registers. By ptracing an
+address into them, you can get a trap on writes or on reads and
+writes).
+
+Rewrite proceed, wait_for_inferior, and normal_stop to clean them up.
+Suggestions:
+
+ 1) Make each test in wait_for_inferior a seperate subroutine
+ call.
+ 2) Combine wait_for_inferior and normal_stop to clean up
+ communication via global variables.
+ 3) See if you can find some way to clean up the global
+ variables that are used; possibly group them by data flow
+ and information content?
+
+Work out some kind of way to allow running the inferior to be done as
+a sub-execution of, eg. breakpoint command lists. Currently running
+the inferior interupts any command list execution. This would require
+some rewriting of wait_for_inferior & friends, and hence should
+probably be done in concert with the above.
+
+Add function arguments to gdb user defined functions.
+
+Add convenience variables that refer to exec file, symbol file,
+selected frame source file, selected frame function, selected frame
+line number, etc.
+
+Add a "suspend" subcommand of the "continue" command to suspend gdb
+while continuing execution of the subprocess. Useful when you are
+debugging servers and you want to dodge out and initiate a connection
+to a server running under gdb.
+
+Make "handle" understand symbolic signal names.
+
+Work out and implement a reasonably general mechanism for multi-threaded
+processies. There are parts of one implemented in convex-dep.c, if
+you want an example.
+
+A standalone version of gdb on the i386 exists. Anyone who wants to
+do some serious working cleaning it up and making it a general
+standalone gdb should contact pace@wheaties.ai.mit.edu.
+
+Add stab information to allow reasonable debugging of inline functions
+(possibly they should show up on a stack backtrace? With a note
+indicating that they weren't "real"?).
+
+Implement support for specifying arbitrary locations of stack frames
+(in practice, this usually requires specification of both the top and
+bottom of the stack frame (fp and sp), since you *must* retrieve the
+pc that was saved in the innermost frame).
+
+Modify the naked "until" command to step until past the current source
+line, rather than past the current pc value. This is tricky simply
+because the low level routines have no way of specifying a multi-line
+step range, and there is no way of saying "don't print stuff when we
+stop" from above (otherwise could just call step many times).
+
+Modify the handling of symbols grouped through BINCL/EINCL stabs to
+allocate a partial symtab for each BINCL/EINCL grouping. This will
+seriously decrease the size of inter-psymtab dependencies and hence
+lessen the amount that needs to be read in when a new source file is
+accessed.
+
+Work out some method of saving breakpoints across the reloading of an
+executable. Probably this should be by saving the commands by which
+the breakpoints were set and re-executing them (as text locations may
+change).
+
+Do an "x/i $pc" after each stepi or nexti.
+
+Modify all of the disassemblers to use printf_filtered to get correct
+more filtering.
+
+Modify gdb to work correctly with Pascal.
+
+Rewrite macros that handle frame chaining and frameless functions.
+They should be able to tell the difference between start, main, and a
+frameless function called from main.
+
+Work out what information would need to be included in an executable
+by the compiler to allow gdb to debug functions which do not have a
+frame pointer. Modify gdb and gcc to do this.
+
+When `attached' to a program (via either OS support or remote
+debugging), gdb should arrange to catch signals which the terminal
+might send, as it is unlikely that the program will be able to notice
+them. SIGINT and SIGTSTP are obvious examples.
+
+Enhance the gdb manual with extra examples where needed.
+
+Arrange for list_command not to use decode_line_1 and thus not require
+symbols to be read in simply to read a source file.
+
+Problem in xgdb; the readline library needs the terminal in CBREAK
+mode for command line editing, but this makes it difficult to dispatch
+on button presses. Possible solution: use a define to replace getc in
+readline.c with a routine that does button dispatches. You should
+probably see XGDB-README before you fiddle with XGDB. Also, someone
+is implementing a new xgdb; it may not be worth while fiddling with
+the old one.
+
+# Local Variables:
+# mode: text
+# End:
diff --git a/gnu/usr.bin/gdb/README.FreeBSD b/gnu/usr.bin/gdb/README.FreeBSD
new file mode 100644
index 0000000..75a30b2
--- /dev/null
+++ b/gnu/usr.bin/gdb/README.FreeBSD
@@ -0,0 +1,15 @@
+This is a greatly pared down version of GDB-4.12 for FreeBSD 1.1.5 that
+supports debugging of shared executables and the new a.out format.
+
+I've collapsed some of the directories and removed lots of files from others.
+All that's included is those necessary to compile on FreeBSD 1.1.5, this was
+to keep the replacement for GDB-3 compact since none of the multiple
+architecture stuff is used. All the documentation has been put in the doc/
+directory.
+
+A full port of each library will probably be done for FreeBSD 2.0 and
+included as system libraries so that other build tools can share them.
+At that time a more complete port of GDB-4 will be done that allows
+configuration for different systems and uses the full libraries.
+
+paul@freefall.cdrom.com
diff --git a/gnu/usr.bin/gdb/README.gnu b/gnu/usr.bin/gdb/README.gnu
new file mode 100644
index 0000000..fa54dec
--- /dev/null
+++ b/gnu/usr.bin/gdb/README.gnu
@@ -0,0 +1,142 @@
+This is GDB, the GNU source-level debugger, presently running under un*x.
+
+Before compiling GDB, you must tell GDB what kind of machine you are
+running on. To do this, type `config.gdb machine', where machine is
+something like `vax' or `sun2'. For a list of valid machine types,
+type `config.gdb'.
+
+Normally config.gdb edits the makefile as necessary. If you have to
+edit the makefile on a standard machine listed in config.gdb this
+should be considered a bug and reported as such.
+
+Once these files are set up, just `make' will do everything,
+producing an executable `gdb' in this directory.
+
+If you want a new (current to this release) version of the manual, you
+will have to use the gdb.texinfo file provided with this distribution.
+The gdb.texinfo file requires the texinfo-format-buffer command from
+emacs 18.55 or later.
+
+About languages other than C...
+
+C++ support has been integrated into gdb. GDB should work with
+FORTRAN programs (if you have problem, please send a bug report), but
+I am not aware of anyone who is working on getting it to use the
+syntax of any language other than C or C++. Pascal programs which use
+sets, subranges, file variables, or nested functions will not
+currently work.
+
+About -gg format...
+
+Currently GDB version 3.x does *not* support GCC's -gg format. This
+is because it (in theory) has fast enough startup on dbx debugging
+format object files that -gg format is unnecessary (and hence
+undesirable, since it wastes space and processing power in gcc). I
+would like to hear people's opinions on the amount of time currently
+spent in startup; is it fast enough?
+
+About remote debugging...
+
+The two files remote-multi.shar and remote-sa.m68k.shar contain two
+examples of a remote stub to be used with remote.c. The the -multi
+file is a general stub that can probably be running on various
+different flavors of unix to allow debugging over a serial line from
+one machine to another. The remote-sa.m68k.shar is designed to run
+standalone on a 68k type cpu and communicate properley with the
+remote.c stub over a serial line.
+
+About reporting bugs...
+
+The correct address for reporting bugs found with gdb is
+"bug-gdb@prep.ai.mit.edu". Please send all bugs to that address.
+
+About xgdb...
+
+xgdb.c was provided to us by the user community; it is not an integral
+part of the gdb distribution. The problem of providing visual
+debugging support on top of gdb is peripheral to the GNU project and
+(at least right now) we can't afford to put time into it. So while we
+will be happy to incorporate user fixes to xgdb.c, we do not guarantee
+that it will work and we will not fix bugs reported in it. Someone is
+working on writing a new XGDB, so improving (e.g. by fixing it so that
+it will work, if it doesn't currently) the current one is not worth it.
+
+For those intersted in auto display of source and the availability of
+an editor while debugging I suggest trying gdb-mode in gnu-emacs.
+Comments on this mode are welcome.
+
+About the machine-dependent files...
+
+m-<machine>.h (param.h is a link to this file).
+This file contains macro definitions that express information
+about the machine's registers, stack frame format and instructions.
+
+<machine>-opcode.h (opcode.h is a link to this file).
+<machine>-pinsn.c (pinsn.c is a link to this file).
+These files contain the information necessary to print instructions
+for your cpu type.
+
+<machine>-dep.c (dep.c is a link to this file).
+Those routines which provide a low level interface to ptrace and which
+tend to be machine-dependent. (The machine-independent routines are in
+`infrun.c' and `inflow.c')
+
+About writing code for GDB...
+
+We appreciate having users contribute code that is of general use, but
+for it to be included in future GDB releases it must be cleanly
+written. We do not want to include changes that will needlessly make future
+maintainance difficult. It is not much harder to do things right, and
+in the long term it is worth it to the GNU project, and probably to
+you individually as well.
+
+Please code according to the GNU coding standards. If you do not have
+a copy, you can request one by sending mail to gnu@prep.ai.mit.edu.
+
+Please try to avoid making machine-specific changes to
+machine-independent files (i.e. all files except "param.h" and
+"dep.c". "pinsn.c" and "opcode.h" are processor-specific but not
+operating system-dependent). If this is unavoidable, put a hook in
+the machine-independent file which calls a (possibly)
+machine-dependent macro (for example, the IGNORE_SYMBOL macro can be
+used for any symbols which need to be ignored on a specific machine.
+Calling IGNORE_SYMBOL in dbxread.c is a lot cleaner than a maze of #if
+defined's). The machine-independent code should do whatever "most"
+machines want if the macro is not defined in param.h. Using #if
+defined can sometimes be OK (e.g. SET_STACK_LIMIT_HUGE) but should be
+conditionalized on a specific feature of an operating system (set in
+param.h) rather than something like #if defined(vax) or #if
+defined(SYSV).
+
+It is better to replace entire routines which may be system-specific,
+rather than put in a whole bunch of hooks which are probably not going
+to be helpful for any purpose other than your changes. For example,
+if you want to modify dbxread.c to deal with DBX debugging symbols
+which are in COFF files rather than BSD a.out files, do something
+along the lines of a macro GET_NEXT_SYMBOL, which could have
+different definitions for COFF and a.out, rather than trying to put
+the necessary changes throughout all the code in dbxread.c that
+currently assumes BSD format.
+
+Please avoid duplicating code. For example, if something needs to be
+changed in read_inferior_memory, it is very painful because there is a
+copy in every dep.c file. The correct way to do this is to put (in
+this case) the standard ptrace interfaces in a separate file ptrace.c,
+which is used by all systems which have ptrace. ptrace.c would deal
+with variations between systems the same way any system-independent
+file would (hooks, #if defined, etc.).
+
+About debugging gdb with itself...
+
+You probably want to do a "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 a M-period .
+
+Also, make sure that you've compiled gdb with your local cc or taken
+appropriate precautions regarding ansification of include files. See
+the Makefile for more information.
+
+The "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
+.gdbinit for more details.
+
diff --git a/gnu/usr.bin/gdb/VERSION b/gnu/usr.bin/gdb/VERSION
new file mode 100644
index 0000000..b849ff8
--- /dev/null
+++ b/gnu/usr.bin/gdb/VERSION
@@ -0,0 +1 @@
+4.11
diff --git a/gnu/usr.bin/gdb/XGdbinit.samp b/gnu/usr.bin/gdb/XGdbinit.samp
new file mode 100644
index 0000000..a99f106
--- /dev/null
+++ b/gnu/usr.bin/gdb/XGdbinit.samp
@@ -0,0 +1,15 @@
+button "show" push-to-file %S
+button "back" pop-file
+button "break in" break %S
+button "break at" break %l
+button delete delete %b%e
+button backtrace
+button up
+button down
+button print print %E
+button print* print *(%E)
+button next
+button step
+button "do upto" until %l%e
+button finish
+button continue cont%e
diff --git a/gnu/usr.bin/gdb/Xgdb.ad b/gnu/usr.bin/gdb/Xgdb.ad
new file mode 100644
index 0000000..5f9fe99
--- /dev/null
+++ b/gnu/usr.bin/gdb/Xgdb.ad
@@ -0,0 +1,8 @@
+Xgdb*geometry: 580x874-0+28
+Xgdb*src*scrollVertical: whenneeded
+Xgdb*src*scrollHorizontal: whenneeded
+Xgdb*src*wrap: never
+Xgdb*src*editType: read
+Xgdb*frame.buttons.allowResize: true
+Xgdb*frame.buttons.skipAdjust: true
+Xgdb*frame*showGrip: false
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..ea29afe
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/Makefile
@@ -0,0 +1,17 @@
+LIB = bfd
+SRCS = archive.c archures.c bfd.c cache.c coffgen.c core.c ctor.c \
+ format.c init.c libbfd.c opncls.c reloc.c seclet.c section.c syms.c \
+ targets.c ecoff.c elf.c srec.c freebsd386.c aout32.c stab-syms.c \
+ cpu-i386.c trad-core.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..204119c
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/README.FreeBSD
@@ -0,0 +1,7 @@
+This is a greatly pared down libbfd directory. Only what's required to build
+gdb-4.12 on FreeBSD was kept.
+
+This is temporary. In FreeBSD 2.0 a fully ported libbfd will likely appear
+as a system library for use by all the build tools.
+
+paul@freefall.cdrom.com
diff --git a/gnu/usr.bin/gdb/bfd/VERSION b/gnu/usr.bin/gdb/bfd/VERSION
new file mode 100644
index 0000000..8bbe6cf
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/VERSION
@@ -0,0 +1 @@
+2.2
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..65a22ff
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/aout-target.h
@@ -0,0 +1,429 @@
+/* Define a target vector and some small routines for a variant of a.out.
+ Copyright (C) 1990, 1991, 1992, 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 "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 bfd_target *
+DEFUN(MY(callback),(abfd),
+ bfd *abfd)
+{
+ struct internal_exec *execp = exec_hdr (abfd);
+
+ /* 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
+
+ /* 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 bfd_target *
+DEFUN(MY(object_p),(abfd),
+ bfd *abfd)
+{
+ struct external_exec exec_bytes; /* Raw exec header from file */
+ struct internal_exec exec; /* Cleaned-up exec header */
+ bfd_target *target;
+
+ if (bfd_read ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd)
+ != EXEC_BYTES_SIZE) {
+ bfd_error = wrong_format;
+ return 0;
+ }
+
+#ifdef NO_SWAP_MAGIC
+ memcpy (&exec.a_info, exec_bytes.e_info, sizeof(exec.a_info));
+#else
+ exec.a_info = bfd_h_get_32 (abfd, exec_bytes.e_info);
+#endif /* NO_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);
+ 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
+DEFUN(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
+
+/* 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
+DEFUN(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
+DEFUN(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
+ adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE;
+ return true;
+}
+#define MY_set_sizes MY(set_sizes)
+#endif
+
+#ifndef MY_backend_data
+static CONST struct aout_backend_data MY(backend_data) = {
+ 0, /* zmagic contiguous */
+ 0, /* text incl header */
+ 0, /* text vma? */
+ MY_set_sizes,
+ 0, /* exec header is counted */
+};
+#define MY_backend_data &MY(backend_data)
+#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_dummy_core_file_failing_command
+#endif
+#ifndef MY_core_file_failing_signal
+#define MY_core_file_failing_signal _bfd_dummy_core_file_failing_signal
+#endif
+#ifndef MY_core_file_matches_executable_p
+#define MY_core_file_matches_executable_p \
+ _bfd_dummy_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_slurp_armap
+#define MY_slurp_armap NAME(aout,slurp_armap)
+#endif
+#ifndef MY_slurp_extended_name_table
+#define MY_slurp_extended_name_table NAME(aout,slurp_extended_name_table)
+#endif
+#ifndef MY_truncate_arname
+#define MY_truncate_arname NAME(aout,truncate_arname)
+#endif
+#ifndef MY_write_armap
+#define MY_write_armap NAME(aout,write_armap)
+#endif
+#ifndef MY_close_and_cleanup
+#define MY_close_and_cleanup NAME(aout,close_and_cleanup)
+#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_openr_next_archived_file
+#define MY_openr_next_archived_file NAME(aout,openr_next_archived_file)
+#endif
+#ifndef MY_find_nearest_line
+#define MY_find_nearest_line NAME(aout,find_nearest_line)
+#endif
+#ifndef MY_generic_stat_arch_elt
+#define MY_generic_stat_arch_elt NAME(aout,generic_stat_arch_elt)
+#endif
+#ifndef MY_sizeof_headers
+#define MY_sizeof_headers NAME(aout,sizeof_headers)
+#endif
+#ifndef MY_bfd_debug_info_start
+#define MY_bfd_debug_info_start NAME(aout,bfd_debug_info_start)
+#endif
+#ifndef MY_bfd_debug_info_end
+#define MY_bfd_debug_info_end NAME(aout,bfd_debug_info_end)
+#endif
+#ifndef MY_bfd_debug_info_accumulat
+#define MY_bfd_debug_info_accumulat NAME(aout,bfd_debug_info_accumulat)
+#endif
+#ifndef MY_reloc_howto_type_lookup
+#define MY_reloc_howto_type_lookup NAME(aout,reloc_type_lookup)
+#endif
+#ifndef MY_make_debug_symbol
+#define MY_make_debug_symbol 0
+#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
+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},
+
+ MY_core_file_failing_command,
+ MY_core_file_failing_signal,
+ MY_core_file_matches_executable_p,
+ MY_slurp_armap,
+ MY_slurp_extended_name_table,
+ MY_truncate_arname,
+ MY_write_armap,
+ MY_close_and_cleanup,
+ MY_set_section_contents,
+ MY_get_section_contents,
+ MY_new_section_hook,
+ MY_get_symtab_upper_bound,
+ MY_get_symtab,
+ MY_get_reloc_upper_bound,
+ MY_canonicalize_reloc,
+ MY_make_empty_symbol,
+ MY_print_symbol,
+ MY_get_symbol_info,
+ MY_get_lineno,
+ MY_set_arch_mach,
+ MY_openr_next_archived_file,
+ MY_find_nearest_line,
+ MY_generic_stat_arch_elt,
+ MY_sizeof_headers,
+ MY_bfd_debug_info_start,
+ MY_bfd_debug_info_end,
+ MY_bfd_debug_info_accumulate,
+ bfd_generic_get_relocated_section_contents,
+ bfd_generic_relax_section,
+ bfd_generic_seclet_link,
+ MY_reloc_howto_type_lookup,
+ MY_make_debug_symbol,
+ (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..84d2087
--- /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-1991 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..1ab4429
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/aoutx.h
@@ -0,0 +1,2568 @@
+/* BFD semi-generic back-end for a.out binaries.
+ 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. */
+
+/*
+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 @code{aoutx.h}
+ and other files which derive functions from the base. One
+ derivation file is @code{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 @code{sunos.c} for sun3 and sun4,
+ @code{newsos3.c} for the Sony NEWS, and @code{demo64.c} for a
+ demonstration of a 64 bit a.out format.
+
+ The base file @code{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
+ @code{aout32.c} and @code{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 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 sunos.c
+
+| #define ARCH 32
+| #define TARGET_NAME "a.out-sunos-big"
+| #define VECNAME sunos_big_vec
+| #include "aoutf1.h"
+
+ requires all the names from aout32.c, and produces the jump vector
+
+| sunos_big_vec
+
+ The 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 <<../include/sys/h-XXX.h>> (for your host). These
+ values, plus the structures and macros defined in <<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 <<host-aout.c>., specify:
+
+| TDEFAULTS = -DDEFAULT_VECTOR=host_aout_big_vec
+| TDEPFILES= host-aout.o trad-core.o
+
+ in the <<config/mt-XXX>> file, and modify configure.in to use the
+ <<mt-XXX>> 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 <assert.h>
+#include <string.h> /* For strchr and friends */
+#include "bfd.h"
+#include <sysdep.h>
+#include <ansidecl.h>
+
+struct external_exec;
+#include "libaout.h"
+#include "libbfd.h"
+#include "aout/aout64.h"
+#include "aout/stab_gnu.h"
+#include "aout/ar.h"
+
+extern void (*bfd_error_trap)();
+
+/*
+SUBSECTION
+ relocations
+
+DESCRIPTION
+ The file @code{aoutx.h} caters for both the @emph{standard}
+ and @emph{extended} forms of a.out relocation records.
+
+ The standard records are characterised by containing 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.
+
+*/
+#define CTOR_TABLE_RELOC_IDX 2
+
+#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),
+{ -1 },
+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),
+};
+
+#define TABLE_SIZE(TABLE) (sizeof(TABLE)/sizeof(TABLE[0]))
+
+CONST struct reloc_howto_struct *
+DEFUN(NAME(aout,reloc_type_lookup),(abfd,code),
+ bfd *abfd AND
+ 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;
+ }
+ 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);
+ 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;
+ }
+}
+
+extern bfd_error_vector_type bfd_error_vector;
+
+/*
+SUBSECTION
+ Internal Entry Points
+
+DESCRIPTION
+ @code{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_<size>_swap_exec_header_in
+
+DESCRIPTION
+ Swaps the information in an executable header taken from a raw
+ byte stream memory image, into the internal exec_header
+ structure.
+
+SYNOPSIS
+ void aout_<size>_swap_exec_header_in,
+ (bfd *abfd,
+ struct external_exec *raw_bytes,
+ struct internal_exec *execp);
+*/
+
+#ifndef NAME_swap_exec_header_in
+void
+DEFUN(NAME(aout,swap_exec_header_in),(abfd, raw_bytes, execp),
+ bfd *abfd AND
+ struct external_exec *raw_bytes AND
+ 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 (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_<size>_swap_exec_header_out
+
+DESCRIPTION
+ Swaps the information in an internal exec header structure
+ into the supplied buffer ready for writing to disk.
+
+SYNOPSIS
+ void aout_<size>_swap_exec_header_out
+ (bfd *abfd,
+ struct internal_exec *execp,
+ struct external_exec *raw_bytes);
+*/
+void
+DEFUN(NAME(aout,swap_exec_header_out),(abfd, execp, raw_bytes),
+ bfd *abfd AND
+ struct internal_exec *execp AND
+ 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);
+}
+
+
+
+/*
+FUNCTION
+ aout_<size>_some_aout_object_p
+
+DESCRIPTION
+ Some A.OUT variant thinks that the file whose format we're
+ checking is an a.out file. Do some more checking, and set up
+ for access if it really is. Call back to the calling
+ environments "finish up" function just before returning, to
+ handle any last-minute setup.
+
+SYNOPSIS
+ bfd_target *aout_<size>_some_aout_object_p
+ (bfd *abfd,
+ bfd_target *(*callback_to_real_object_p)());
+*/
+
+bfd_target *
+DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p),
+ bfd *abfd AND
+ struct internal_exec *execp AND
+ bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *)))
+{
+ struct aout_data_struct *rawptr, *oldrawptr;
+ bfd_target *result;
+
+ rawptr = (struct aout_data_struct *) bfd_zalloc (abfd, sizeof (struct aout_data_struct ));
+ if (rawptr == NULL) {
+ 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_MAGIC (*execp) == ZMAGIC)
+ {
+ abfd->flags |= D_PAGED|WP_TEXT;
+ adata(abfd).magic = z_magic;
+ }
+ else if (N_MAGIC (*execp) == NMAGIC)
+ {
+ abfd->flags |= WP_TEXT;
+ adata(abfd).magic = n_magic;
+ }
+ else
+ adata(abfd).magic = o_magic;
+
+ 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;
+
+ /* Create the sections. This is raunchy, but bfd_close wants to reclaim
+ them. */
+
+ obj_textsec (abfd) = bfd_make_section_old_way (abfd, ".text");
+ obj_datasec (abfd) = bfd_make_section_old_way (abfd, ".data");
+ obj_bsssec (abfd) = bfd_make_section_old_way (abfd, ".bss");
+
+#if 0
+ (void)bfd_make_section (abfd, ".text");
+ (void)bfd_make_section (abfd, ".data");
+ (void)bfd_make_section (abfd, ".bss");
+#endif
+
+ 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 addersses 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);
+
+ /* 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;
+ 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_<size>_mkobject
+
+DESCRIPTION
+ This routine initializes a BFD for use with a.out files.
+
+SYNOPSIS
+ boolean aout_<size>_mkobject, (bfd *);
+*/
+
+boolean
+DEFUN(NAME(aout,mkobject),(abfd),
+ bfd *abfd)
+{
+ struct aout_data_struct *rawptr;
+
+ bfd_error = system_call_error;
+
+ /* Use an intermediate variable for clarity */
+ rawptr = (struct aout_data_struct *)bfd_zalloc (abfd, sizeof (struct aout_data_struct ));
+
+ if (rawptr == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ abfd->tdata.aout_data = rawptr;
+ exec_hdr (abfd) = &(rawptr->e);
+
+ /* For simplicity's sake we just make all the sections right here. */
+
+ obj_textsec (abfd) = (asection *)NULL;
+ obj_datasec (abfd) = (asection *)NULL;
+ obj_bsssec (abfd) = (asection *)NULL;
+ bfd_make_section (abfd, ".text");
+ bfd_make_section (abfd, ".data");
+ bfd_make_section (abfd, ".bss");
+ bfd_make_section (abfd, BFD_ABS_SECTION_NAME);
+ bfd_make_section (abfd, BFD_UND_SECTION_NAME);
+ bfd_make_section (abfd, BFD_COM_SECTION_NAME);
+
+ return true;
+}
+
+
+/*
+FUNCTION
+ aout_<size>_machine_type
+
+DESCRIPTION
+ Keep track of machine architecture and machine type for
+ a.out's. Return the machine_type for a particular
+ arch&machine, or M_UNKNOWN if that exact arch&machine can't be
+ represented in a.out format.
+
+ If the architecture is understood, machine type 0 (default)
+ should always be understood.
+
+SYNOPSIS
+ enum machine_type aout_<size>_machine_type
+ (enum bfd_architecture arch,
+ unsigned long machine));
+*/
+
+enum machine_type
+DEFUN(NAME(aout,machine_type),(arch, machine),
+ enum bfd_architecture arch AND
+ unsigned long machine)
+{
+ enum machine_type arch_flags;
+
+ arch_flags = M_UNKNOWN;
+
+ 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; 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;
+
+ default:
+ arch_flags = M_UNKNOWN;
+ }
+ return arch_flags;
+}
+
+
+/*
+FUNCTION
+ aout_<size>_set_arch_mach
+
+DESCRIPTION
+ Sets the architecture and the machine of the BFD to those
+ values supplied. Verifies that the format can support the
+ architecture required.
+
+SYNOPSIS
+ boolean aout_<size>_set_arch_mach,
+ (bfd *,
+ enum bfd_architecture,
+ unsigned long machine));
+*/
+
+boolean
+DEFUN(NAME(aout,set_arch_mach),(abfd, arch, machine),
+ bfd *abfd AND
+ enum bfd_architecture arch AND
+ unsigned long machine)
+{
+ if (! bfd_default_set_arch_mach (abfd, arch, machine))
+ return false;
+
+ if (arch != bfd_arch_unknown &&
+ NAME(aout,machine_type) (arch, machine) == M_UNKNOWN)
+ return false; /* We can't represent this type */
+
+ /* 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);
+}
+
+boolean
+DEFUN (NAME (aout,adjust_sizes_and_vmas), (abfd, text_size, text_end),
+ bfd *abfd AND bfd_size_type *text_size AND file_ptr *text_end)
+{
+ struct internal_exec *execp = exec_hdr (abfd);
+ if ((obj_textsec (abfd) == NULL) || (obj_datasec (abfd) == NULL))
+ {
+ bfd_error = invalid_operation;
+ 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 (adata(abfd).magic == undecided_magic)
+ {
+ if (abfd->flags & D_PAGED)
+ /* Whether or not WP_TEXT is set -- let D_PAGED override. */
+ /* @@ What about QMAGIC? */
+ 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:
+ {
+ file_ptr pos = adata (abfd).exec_bytes_size;
+ bfd_vma vma = 0;
+ int pad = 0;
+
+ obj_textsec(abfd)->filepos = pos;
+ pos += obj_textsec(abfd)->_raw_size;
+ vma += obj_textsec(abfd)->_raw_size;
+ 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;
+ 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;
+ 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);
+ }
+ break;
+ case z_magic:
+ {
+ bfd_size_type data_pad, text_pad;
+ file_ptr text_end;
+ CONST struct aout_backend_data *abdp;
+ int ztih;
+ bfd_vma data_vma;
+
+ abdp = aout_backend_info (abfd);
+ ztih = abdp && abdp->text_includes_header;
+ obj_textsec(abfd)->filepos = (ztih
+ ? adata(abfd).exec_bytes_size
+ : adata(abfd).page_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. */
+ text_end = obj_textsec(abfd)->filepos + obj_textsec(abfd)->_raw_size;
+ text_pad = BFD_ALIGN (text_end, adata(abfd).page_size) - text_end;
+ obj_textsec(abfd)->_raw_size += text_pad;
+ text_end += text_pad;
+
+ 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);
+ }
+ data_vma = obj_datasec(abfd)->vma;
+ 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;
+ N_SET_MAGIC (*execp, ZMAGIC);
+ /* Spec says data section should be rounded up to page boundary. */
+ /* If extra space in page is left after 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. */
+ 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;
+
+ if (!obj_bsssec(abfd)->user_set_vma)
+ obj_bsssec(abfd)->vma = (obj_datasec(abfd)->vma
+ + obj_datasec(abfd)->_raw_size);
+ if (data_pad > obj_bsssec(abfd)->_raw_size)
+ execp->a_bss = 0;
+ else
+ execp->a_bss = obj_bsssec(abfd)->_raw_size - data_pad;
+ }
+ break;
+ case n_magic:
+ {
+ file_ptr pos = adata(abfd).exec_bytes_size;
+ bfd_vma vma = 0;
+ int pad;
+
+ 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;
+ 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;
+
+ if (!obj_bsssec(abfd)->user_set_vma)
+ obj_bsssec(abfd)->vma = vma;
+ else
+ vma = obj_bsssec(abfd)->vma;
+ }
+ 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);
+ 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_<size>_new_section_hook
+
+DESCRIPTION
+ Called by the BFD in response to a @code{bfd_make_section}
+ request.
+
+SYNOPSIS
+ boolean aout_<size>_new_section_hook,
+ (bfd *abfd,
+ asection *newsect));
+*/
+boolean
+DEFUN(NAME(aout,new_section_hook),(abfd, newsect),
+ bfd *abfd AND
+ 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 | N_EXT;
+ return true;
+ }
+
+ if (obj_datasec(abfd) == NULL && !strcmp(newsect->name, ".data")) {
+ obj_datasec(abfd) = newsect;
+ newsect->target_index = N_DATA | N_EXT;
+ return true;
+ }
+
+ if (obj_bsssec(abfd) == NULL && !strcmp(newsect->name, ".bss")) {
+ obj_bsssec(abfd) = newsect;
+ newsect->target_index = N_BSS | N_EXT;
+ return true;
+ }
+
+ }
+
+ /* We allow more than three sections internally */
+ return true;
+}
+
+boolean
+DEFUN(NAME(aout,set_section_contents),(abfd, section, location, offset, count),
+ bfd *abfd AND
+ sec_ptr section AND
+ PTR location AND
+ file_ptr offset AND
+ 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))
+ {
+ bfd_seek (abfd, section->filepos + offset, SEEK_SET);
+
+ if (count) {
+ return (bfd_write ((PTR)location, 1, count, abfd) == count) ?
+ true : false;
+ }
+ return true;
+ }
+ return true;
+}
+
+/* Classify stabs symbols */
+
+#define sym_in_text_section(sym) \
+ (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_TEXT)
+
+#define sym_in_data_section(sym) \
+ (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_DATA)
+
+#define sym_in_bss_section(sym) \
+ (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_BSS)
+
+/* Symbol is undefined if type is N_UNDF|N_EXT and if it has
+ zero in the "value" field. Nonzeroes there are fortrancommon
+ symbols. */
+#define sym_is_undefined(sym) \
+ ((sym)->type == (N_UNDF | N_EXT) && (sym)->symbol.value == 0)
+
+/* Symbol is a global definition if N_EXT is on and if it has
+ a nonzero type field. */
+#define sym_is_global_defn(sym) \
+ (((sym)->type & N_EXT) && (sym)->type & N_TYPE)
+
+/* Symbol is debugger info if any bits outside N_TYPE or N_EXT
+ are on. */
+#define sym_is_debugger_info(sym) \
+ (((sym)->type & ~(N_EXT | N_TYPE)) || (sym)->type == N_FN)
+
+#define sym_is_fortrancommon(sym) \
+ (((sym)->type == (N_EXT)) && (sym)->symbol.value != 0)
+
+/* Symbol is absolute if it has N_ABS set */
+#define sym_is_absolute(sym) \
+ (((sym)->type & N_TYPE)== N_ABS)
+
+
+#define sym_is_indirect(sym) \
+ (((sym)->type & N_ABS)== N_ABS)
+
+/* Only in their own functions for ease of debugging; when sym flags have
+ stabilised these should be inlined into their (single) caller */
+
+static void
+DEFUN (translate_from_native_sym_flags, (sym_pointer, cache_ptr, abfd),
+ struct external_nlist *sym_pointer AND
+ aout_symbol_type * cache_ptr AND
+ bfd * abfd)
+{
+ cache_ptr->symbol.section = 0;
+ switch (cache_ptr->type & N_TYPE)
+ {
+ case N_SETA:
+ case N_SETT:
+ case N_SETD:
+ case N_SETB:
+ {
+ char *copy = bfd_alloc (abfd, strlen (cache_ptr->symbol.name) + 1);
+ asection *section;
+ asection *into_section;
+
+ arelent_chain *reloc = (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain));
+ strcpy (copy, cache_ptr->symbol.name);
+
+ /* Make sure that this bfd has a section with the right contructor
+ name */
+ section = bfd_get_section_by_name (abfd, copy);
+ if (!section)
+ section = bfd_make_section (abfd, copy);
+
+ /* Build a relocation entry for the constructor */
+ switch ((cache_ptr->type & N_TYPE))
+ {
+ case N_SETA:
+ into_section = &bfd_abs_section;
+ cache_ptr->type = N_ABS;
+ break;
+ case N_SETT:
+ into_section = (asection *) obj_textsec (abfd);
+ cache_ptr->type = N_TEXT;
+ break;
+ case N_SETD:
+ into_section = (asection *) obj_datasec (abfd);
+ cache_ptr->type = N_DATA;
+ break;
+ case N_SETB:
+ into_section = (asection *) obj_bsssec (abfd);
+ cache_ptr->type = N_BSS;
+ break;
+ default:
+ abort ();
+ }
+
+ /* Build a relocation pointing into the constuctor section
+ pointing at the symbol in the set vector specified */
+
+ reloc->relent.addend = cache_ptr->symbol.value;
+ cache_ptr->symbol.section = into_section->symbol->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 - probably __CTOR__ or __DTOR__ but we don't
+ really care, 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;
+
+
+ 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 += sizeof (int *);
+
+ reloc->relent.howto
+ = (obj_reloc_entry_size(abfd) == RELOC_EXT_SIZE
+ ? howto_table_ext : howto_table_std)
+ + CTOR_TABLE_RELOC_IDX;
+ cache_ptr->symbol.flags |= BSF_CONSTRUCTOR;
+ }
+ break;
+ default:
+ if (cache_ptr->type == N_WARNING)
+ {
+ /* This symbol is the text of a warning message, the next symbol
+ is the symbol to associate the warning with */
+ 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));
+
+ /* We furgle with the next symbol in place.
+ We don't want it to be undefined, we'll trample the type */
+ (sym_pointer + 1)->e_type[0] = 0xff;
+ break;
+ }
+ if ((cache_ptr->type | N_EXT) == (N_INDR | N_EXT))
+ {
+ /* Two symbols in a row for an INDR message. The first symbol
+ contains the name we will match, the second symbol contains
+ the name the first name is translated into. It is supplied to
+ us undefined. This is good, since we want to pull in any files
+ which define it */
+ cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT;
+
+ /* @@ 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;
+ }
+
+ else if (sym_is_debugger_info (cache_ptr))
+ {
+ cache_ptr->symbol.flags = BSF_DEBUGGING;
+ /* Work out the section correct for this symbol */
+ switch (cache_ptr->type & N_TYPE)
+ {
+ case N_TEXT:
+ case N_FN:
+ cache_ptr->symbol.section = obj_textsec (abfd);
+ cache_ptr->symbol.value -= obj_textsec (abfd)->vma;
+ break;
+ case N_DATA:
+ cache_ptr->symbol.value -= obj_datasec (abfd)->vma;
+ cache_ptr->symbol.section = obj_datasec (abfd);
+ break;
+ case N_BSS:
+ cache_ptr->symbol.section = obj_bsssec (abfd);
+ cache_ptr->symbol.value -= obj_bsssec (abfd)->vma;
+ break;
+ default:
+ case N_ABS:
+
+ cache_ptr->symbol.section = &bfd_abs_section;
+ break;
+ }
+ }
+ else
+ {
+
+ if (sym_is_fortrancommon (cache_ptr))
+ {
+ cache_ptr->symbol.flags = 0;
+ cache_ptr->symbol.section = &bfd_com_section;
+ }
+ else
+ {
+
+
+ }
+
+ /* In a.out, the value of a symbol is always relative to the
+ * start of the file, if this is a data symbol we'll subtract
+ * the size of the text section to get the section relative
+ * value. If this is a bss symbol (which would be strange)
+ * we'll subtract the size of the previous two sections
+ * to find the section relative address.
+ */
+
+ if (sym_in_text_section (cache_ptr))
+ {
+ cache_ptr->symbol.value -= obj_textsec (abfd)->vma;
+ cache_ptr->symbol.section = obj_textsec (abfd);
+ }
+ else if (sym_in_data_section (cache_ptr))
+ {
+ cache_ptr->symbol.value -= obj_datasec (abfd)->vma;
+ cache_ptr->symbol.section = obj_datasec (abfd);
+ }
+ else if (sym_in_bss_section (cache_ptr))
+ {
+ cache_ptr->symbol.section = obj_bsssec (abfd);
+ cache_ptr->symbol.value -= obj_bsssec (abfd)->vma;
+ }
+ else if (sym_is_undefined (cache_ptr))
+ {
+ cache_ptr->symbol.flags = 0;
+ cache_ptr->symbol.section = &bfd_und_section;
+ }
+ else if (sym_is_absolute (cache_ptr))
+ {
+ cache_ptr->symbol.section = &bfd_abs_section;
+ }
+
+ if (sym_is_global_defn (cache_ptr))
+ {
+ cache_ptr->symbol.flags = BSF_GLOBAL | BSF_EXPORT;
+ }
+ else
+ {
+ cache_ptr->symbol.flags = BSF_LOCAL;
+ }
+ }
+ }
+ if (cache_ptr->symbol.section == 0)
+ abort ();
+}
+
+
+
+static void
+DEFUN(translate_to_native_sym_flags,(sym_pointer, cache_ptr, abfd),
+ struct external_nlist *sym_pointer AND
+ asymbol *cache_ptr AND
+ bfd *abfd)
+{
+ 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;
+
+
+ /* We attempt to order these tests by decreasing frequency of success,
+ according to tcov when linking the linker. */
+ if (bfd_get_output_section(cache_ptr) == &bfd_abs_section) {
+ sym_pointer->e_type[0] |= N_ABS;
+ }
+ else if (bfd_get_output_section(cache_ptr) == obj_textsec (abfd)) {
+ sym_pointer->e_type[0] |= N_TEXT;
+ }
+ else if (bfd_get_output_section(cache_ptr) == obj_datasec (abfd)) {
+ sym_pointer->e_type[0] |= N_DATA;
+ }
+ else if (bfd_get_output_section(cache_ptr) == obj_bsssec (abfd)) {
+ sym_pointer->e_type[0] |= N_BSS;
+ }
+ else if (bfd_get_output_section(cache_ptr) == &bfd_und_section)
+ {
+ sym_pointer->e_type[0] = (N_UNDF | N_EXT);
+ }
+ else if (bfd_get_output_section(cache_ptr) == &bfd_ind_section)
+ {
+ sym_pointer->e_type[0] = N_INDR;
+ }
+ else if (bfd_is_com_section (bfd_get_output_section (cache_ptr))) {
+ sym_pointer->e_type[0] = (N_UNDF | N_EXT);
+ }
+ else {
+ if (cache_ptr->section->output_section)
+ {
+
+ bfd_error_vector.nonrepresentable_section(abfd,
+ bfd_get_output_section(cache_ptr)->name);
+ }
+ else
+ {
+ bfd_error_vector.nonrepresentable_section(abfd,
+ cache_ptr->section->name);
+
+ }
+
+ }
+ /* Turn the symbol from section relative to absolute again */
+
+ value += cache_ptr->section->output_section->vma + cache_ptr->section->output_offset ;
+
+
+ if (cache_ptr->flags & (BSF_WARNING)) {
+ (sym_pointer+1)->e_type[0] = 1;
+ }
+
+ if (cache_ptr->flags & BSF_DEBUGGING) {
+ sym_pointer->e_type[0] = ((aout_symbol_type *)cache_ptr)->type;
+ }
+ else if (cache_ptr->flags & (BSF_GLOBAL | BSF_EXPORT)) {
+ sym_pointer->e_type[0] |= N_EXT;
+ }
+ if (cache_ptr->flags & BSF_CONSTRUCTOR) {
+ 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;
+ }
+
+ PUT_WORD(abfd, value, sym_pointer->e_value);
+}
+
+/* Native-level interface to symbols. */
+
+/* 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. */
+
+asymbol *
+DEFUN(NAME(aout,make_empty_symbol),(abfd),
+ bfd *abfd)
+{
+ aout_symbol_type *new =
+ (aout_symbol_type *)bfd_zalloc (abfd, sizeof (aout_symbol_type));
+ new->symbol.the_bfd = abfd;
+
+ return &new->symbol;
+}
+
+boolean
+DEFUN(NAME(aout,slurp_symbol_table),(abfd),
+ bfd *abfd)
+{
+ bfd_size_type symbol_size;
+ bfd_size_type string_size;
+ unsigned char string_chars[BYTES_IN_WORD];
+ struct external_nlist *syms;
+ char *strings;
+ aout_symbol_type *cached;
+
+ /* If there's no work to be done, don't do any */
+ if (obj_aout_symbols (abfd) != (aout_symbol_type *)NULL) return true;
+ symbol_size = exec_hdr(abfd)->a_syms;
+ if (symbol_size == 0)
+ {
+ bfd_error = no_symbols;
+ return false;
+ }
+
+ bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET);
+ if (bfd_read ((PTR)string_chars, BYTES_IN_WORD, 1, abfd) != BYTES_IN_WORD)
+ return false;
+ string_size = GET_WORD (abfd, string_chars);
+
+ strings =(char *) bfd_alloc(abfd, string_size + 1);
+ cached = (aout_symbol_type *)
+ bfd_zalloc(abfd, (bfd_size_type)(bfd_get_symcount (abfd) * sizeof(aout_symbol_type)));
+
+ /* malloc this, so we can free it if simply. The symbol caching
+ might want to allocate onto the bfd's obstack */
+ syms = (struct external_nlist *) bfd_xmalloc(symbol_size);
+ bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET);
+ if (bfd_read ((PTR)syms, 1, symbol_size, abfd) != symbol_size)
+ {
+ bailout:
+ if (syms)
+ free (syms);
+ if (cached)
+ bfd_release (abfd, cached);
+ if (strings)
+ bfd_release (abfd, strings);
+ return false;
+ }
+
+ bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET);
+ if (bfd_read ((PTR)strings, 1, string_size, abfd) != string_size)
+ {
+ goto bailout;
+ }
+ strings[string_size] = 0; /* Just in case. */
+
+ /* OK, now walk the new symtable, cacheing symbol properties */
+ {
+ register struct external_nlist *sym_pointer;
+ register struct external_nlist *sym_end = syms + bfd_get_symcount (abfd);
+ register aout_symbol_type *cache_ptr = cached;
+
+ /* Run through table and copy values */
+ for (sym_pointer = syms, cache_ptr = cached;
+ sym_pointer < sym_end; sym_pointer ++, cache_ptr++)
+ {
+ long x = GET_WORD(abfd, sym_pointer->e_strx);
+ cache_ptr->symbol.the_bfd = abfd;
+ if (x == 0)
+ cache_ptr->symbol.name = "";
+ else if (x >= 0 && x < string_size)
+ cache_ptr->symbol.name = x + strings;
+ else
+ goto bailout;
+
+ cache_ptr->symbol.value = GET_SWORD(abfd, sym_pointer->e_value);
+ cache_ptr->desc = bfd_h_get_16(abfd, sym_pointer->e_desc);
+ cache_ptr->other = bfd_h_get_8(abfd, sym_pointer->e_other);
+ cache_ptr->type = bfd_h_get_8(abfd, sym_pointer->e_type);
+ cache_ptr->symbol.udata = 0;
+ translate_from_native_sym_flags (sym_pointer, cache_ptr, abfd);
+ }
+ }
+
+ obj_aout_symbols (abfd) = cached;
+ free((PTR)syms);
+
+ return true;
+}
+
+
+/* Possible improvements:
+ + look for strings matching trailing substrings of other strings
+ + better data structures? balanced trees?
+ + smaller per-string or per-symbol data? re-use some of the symbol's
+ data fields?
+ + also 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?)
+ + rip this out of here, put it into its own file in bfd or libiberty, so
+ coff and elf can use it too. I'll work on this soon, but have more
+ pressing tasks right now.
+
+ A hash table might(?) be more efficient for handling exactly the cases that
+ are handled now, but for trailing substring matches, I think we want to
+ examine the `nearest' values (reverse-)lexically, not merely impose a strict
+ order, nor look only for exact-match or not-match. I don't think a hash
+ table would be very useful for that, and I don't feel like fleshing out two
+ completely different implementations. [raeburn:930419.0331EDT] */
+
+struct stringtab_entry {
+ /* Hash value for this string. Only useful so long as we aren't doing
+ substring matches. */
+ unsigned int hash;
+
+ /* Next node to look at, depending on whether the hash value of the string
+ being searched for is less than or greater than the hash value of the
+ current node. For now, `equal to' is lumped in with `greater than', for
+ space efficiency. It's not a common enough case to warrant another field
+ to be used for all nodes. */
+ struct stringtab_entry *less;
+ struct stringtab_entry *greater;
+
+ /* The string itself. */
+ CONST char *string;
+
+ /* The index allocated for this string. */
+ bfd_size_type index;
+
+#ifdef GATHER_STATISTICS
+ /* How many references have there been to this string? (Not currently used;
+ could be dumped out for anaylsis, if anyone's interested.) */
+ unsigned long count;
+#endif
+
+ /* Next node in linked list, in suggested output order. */
+ struct stringtab_entry *next_to_output;
+};
+
+struct stringtab_data {
+ /* Tree of string table entries. */
+ struct stringtab_entry *strings;
+
+ /* Fudge factor used to center top node of tree. */
+ int hash_zero;
+
+ /* Next index value to issue. */
+ bfd_size_type index;
+
+ /* Index used for empty strings. Cached here because checking for them
+ is really easy, and we can avoid searching the tree. */
+ bfd_size_type empty_string_index;
+
+ /* These fields indicate the two ends of a singly-linked list that indicates
+ the order strings should be written out in. Use this order, and no
+ seeking will need to be done, so output efficiency should be maximized. */
+ struct stringtab_entry **end;
+ struct stringtab_entry *output_order;
+
+#ifdef GATHER_STATISTICS
+ /* Number of strings which duplicate strings already in the table. */
+ unsigned long duplicates;
+
+ /* Number of bytes saved by not having to write all the duplicate strings. */
+ unsigned long bytes_saved;
+
+ /* Number of zero-length strings. Currently, these all turn into
+ references to the null byte at the end of the first string. In some
+ cases (possibly not all? explore this...), it should be possible to
+ simply write out a zero index value. */
+ unsigned long empty_strings;
+
+ /* Number of times the hash values matched but the strings were different.
+ Note that this includes the number of times the other string(s) occurs, so
+ there may only be two strings hashing to the same value, even if this
+ number is very large. */
+ unsigned long bad_hash_matches;
+
+ /* Null strings aren't counted in this one.
+ This will probably only be nonzero if we've got an input file
+ which was produced by `ld -r' (i.e., it's already been processed
+ through this code). Under some operating systems, native tools
+ may make all empty strings have the same index; but the pointer
+ check won't catch those, because to get to that stage we'd already
+ have to compute the checksum, which requires reading the string,
+ so we short-circuit that case with empty_string_index above. */
+ unsigned long pointer_matches;
+
+ /* Number of comparisons done. I figure with the algorithms in use below,
+ the average number of comparisons done (per symbol) should be roughly
+ log-base-2 of the number of unique strings. */
+ unsigned long n_compares;
+#endif
+};
+
+/* Some utility functions for the string table code. */
+
+/* For speed, only hash on the first this many bytes of strings.
+ This number was chosen by profiling ld linking itself, with -g. */
+#define HASHMAXLEN 25
+
+#define HASH_CHAR(c) (sum ^= sum >> 20, sum ^= sum << 7, sum += (c))
+
+static INLINE unsigned int
+hash (string, len)
+ unsigned char *string;
+ register unsigned int len;
+{
+ register unsigned int sum = 0;
+
+ if (len > HASHMAXLEN)
+ {
+ HASH_CHAR (len);
+ len = HASHMAXLEN;
+ }
+
+ while (len--)
+ {
+ HASH_CHAR (*string++);
+ }
+ return sum;
+}
+
+static INLINE void
+stringtab_init (tab)
+ struct stringtab_data *tab;
+{
+ tab->strings = 0;
+ tab->output_order = 0;
+ tab->end = &tab->output_order;
+
+ /* Initial string table length includes size of length field. */
+ tab->index = BYTES_IN_WORD;
+ tab->empty_string_index = -1;
+#ifdef GATHER_STATISTICS
+ tab->duplicates = 0;
+ tab->empty_strings = 0;
+ tab->bad_hash_matches = 0;
+ tab->pointer_matches = 0;
+ tab->bytes_saved = 0;
+ tab->n_compares = 0;
+#endif
+}
+
+static INLINE int
+compare (entry, str, hash)
+ struct stringtab_entry *entry;
+ CONST char *str;
+ unsigned int hash;
+{
+ return hash - entry->hash;
+}
+
+#ifdef GATHER_STATISTICS
+/* Don't want to have to link in math library with all bfd applications... */
+static INLINE double
+log2 (num)
+ int num;
+{
+ double d = num;
+ int n = 0;
+ while (d >= 2.0)
+ n++, d /= 2.0;
+ return ((d > 1.41) ? 0.5 : 0) + n;
+}
+#endif
+
+/* Main string table routines. */
+/* Returns index in string table. Whether or not this actually adds an
+ entry into the string table should be irrelevant -- it just has to
+ return a valid index. */
+static bfd_size_type
+add_to_stringtab (abfd, str, tab, check)
+ bfd *abfd;
+ CONST char *str;
+ struct stringtab_data *tab;
+ int check;
+{
+ struct stringtab_entry **ep;
+ register struct stringtab_entry *entry;
+ unsigned int hashval, len;
+
+ if (str[0] == 0)
+ {
+ bfd_size_type index;
+ CONST bfd_size_type minus_one = -1;
+
+#ifdef GATHER_STATISTICS
+ tab->empty_strings++;
+#endif
+ index = tab->empty_string_index;
+ if (index != minus_one)
+ {
+ got_empty:
+#ifdef GATHER_STATISTICS
+ tab->bytes_saved++;
+ tab->duplicates++;
+#endif
+ return index;
+ }
+
+ /* Need to find it. */
+ entry = tab->strings;
+ if (entry)
+ {
+ index = entry->index + strlen (entry->string);
+ tab->empty_string_index = index;
+ goto got_empty;
+ }
+ len = 0;
+ }
+ else
+ len = strlen (str);
+
+ /* The hash_zero value is chosen such that the first symbol gets a value of
+ zero. With a balanced tree, this wouldn't be very useful, but without it,
+ we might get a more even split at the top level, instead of skewing it
+ badly should hash("/usr/lib/crt0.o") (or whatever) be far from zero. */
+ hashval = hash (str, len) ^ tab->hash_zero;
+ ep = &tab->strings;
+ if (!*ep)
+ {
+ tab->hash_zero = hashval;
+ hashval = 0;
+ goto add_it;
+ }
+
+ while (*ep)
+ {
+ register int cmp;
+
+ entry = *ep;
+#ifdef GATHER_STATISTICS
+ tab->n_compares++;
+#endif
+ cmp = compare (entry, str, hashval);
+ /* The not-equal cases are more frequent, so check them first. */
+ if (cmp > 0)
+ ep = &entry->greater;
+ else if (cmp < 0)
+ ep = &entry->less;
+ else
+ {
+ if (entry->string == str)
+ {
+#ifdef GATHER_STATISTICS
+ tab->pointer_matches++;
+#endif
+ goto match;
+ }
+ /* Compare the first bytes to save a function call if they
+ don't match. */
+ if (entry->string[0] == str[0] && !strcmp (entry->string, str))
+ {
+ match:
+#ifdef GATHER_STATISTICS
+ entry->count++;
+ tab->bytes_saved += len + 1;
+ tab->duplicates++;
+#endif
+ /* If we're in the linker, and the new string is from a new
+ input file which might have already had these reductions
+ run over it, we want to keep the new string pointer. I
+ don't think we're likely to see any (or nearly as many,
+ at least) cases where a later string is in the same location
+ as an earlier one rather than this one. */
+ entry->string = str;
+ return entry->index;
+ }
+#ifdef GATHER_STATISTICS
+ tab->bad_hash_matches++;
+#endif
+ ep = &entry->greater;
+ }
+ }
+
+ /* If we get here, nothing that's in the table already matched.
+ EP points to the `next' field at the end of the chain; stick a
+ new entry on here. */
+ add_it:
+ entry = (struct stringtab_entry *)
+ bfd_alloc_by_size_t (abfd, sizeof (struct stringtab_entry));
+
+ entry->less = entry->greater = 0;
+ entry->hash = hashval;
+ entry->index = tab->index;
+ entry->string = str;
+ entry->next_to_output = 0;
+#ifdef GATHER_STATISTICS
+ entry->count = 1;
+#endif
+
+ assert (*tab->end == 0);
+ *(tab->end) = entry;
+ tab->end = &entry->next_to_output;
+ assert (*tab->end == 0);
+
+ {
+ tab->index += len + 1;
+ if (len == 0)
+ tab->empty_string_index = entry->index;
+ }
+ assert (*ep == 0);
+ *ep = entry;
+ return entry->index;
+}
+
+static void
+emit_strtab (abfd, tab)
+ bfd *abfd;
+ struct stringtab_data *tab;
+{
+ struct stringtab_entry *entry;
+#ifdef GATHER_STATISTICS
+ int count = 0;
+#endif
+
+ /* Be sure to put string length into correct byte ordering before writing
+ it out. */
+ char buffer[BYTES_IN_WORD];
+
+ PUT_WORD (abfd, tab->index, (unsigned char *) buffer);
+ bfd_write ((PTR) buffer, 1, BYTES_IN_WORD, abfd);
+
+ for (entry = tab->output_order; entry; entry = entry->next_to_output)
+ {
+ bfd_write ((PTR) entry->string, 1, strlen (entry->string) + 1, abfd);
+#ifdef GATHER_STATISTICS
+ count++;
+#endif
+ }
+
+#ifdef GATHER_STATISTICS
+ /* Short form only, for now.
+ To do: Specify output file. Conditionalize on environment? Detailed
+ analysis if desired. */
+ {
+ int n_syms = bfd_get_symcount (abfd);
+
+ fprintf (stderr, "String table data for output file:\n");
+ fprintf (stderr, " %8d symbols output\n", n_syms);
+ fprintf (stderr, " %8d duplicate strings\n", tab->duplicates);
+ fprintf (stderr, " %8d empty strings\n", tab->empty_strings);
+ fprintf (stderr, " %8d unique strings output\n", count);
+ fprintf (stderr, " %8d pointer matches\n", tab->pointer_matches);
+ fprintf (stderr, " %8d bytes saved\n", tab->bytes_saved);
+ fprintf (stderr, " %8d bad hash matches\n", tab->bad_hash_matches);
+ fprintf (stderr, " %8d hash-val comparisons\n", tab->n_compares);
+ if (n_syms)
+ {
+ double n_compares = tab->n_compares;
+ double avg_compares = n_compares / n_syms;
+ /* The second value here should usually be near one. */
+ fprintf (stderr,
+ "\t average %f comparisons per symbol (%f * log2 nstrings)\n",
+ avg_compares, avg_compares / log2 (count));
+ }
+ }
+#endif
+
+/* Old code:
+ unsigned int count;
+ generic = bfd_get_outsymbols(abfd);
+ for (count = 0; count < bfd_get_symcount(abfd); count++)
+ {
+ asymbol *g = *(generic++);
+
+ if (g->name)
+ {
+ size_t length = strlen(g->name)+1;
+ bfd_write((PTR)g->name, 1, length, abfd);
+ }
+ g->KEEPIT = (KEEPITTYPE) count;
+ } */
+}
+
+void
+DEFUN(NAME(aout,write_syms),(abfd),
+ bfd *abfd)
+{
+ unsigned int count ;
+ asymbol **generic = bfd_get_outsymbols (abfd);
+ struct stringtab_data strtab;
+
+ stringtab_init (&strtab);
+
+ for (count = 0; count < bfd_get_symcount (abfd); count++)
+ {
+ asymbol *g = generic[count];
+ struct external_nlist nsp;
+
+ if (g->name)
+ PUT_WORD (abfd, add_to_stringtab (abfd, g->name, &strtab),
+ (unsigned char *) nsp.e_strx);
+ else
+ PUT_WORD (abfd, 0, (unsigned char *)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);
+ }
+
+ translate_to_native_sym_flags (&nsp, g, abfd);
+
+ bfd_write((PTR)&nsp,1,EXTERNAL_NLIST_SIZE, abfd);
+
+ /* NB: `KEEPIT' currently overlays `flags', so set this only
+ here, at the end. */
+ g->KEEPIT = count;
+ }
+
+ emit_strtab (abfd, &strtab);
+}
+
+
+unsigned int
+DEFUN(NAME(aout,get_symtab),(abfd, location),
+ bfd *abfd AND
+ asymbol **location)
+{
+ unsigned int counter = 0;
+ aout_symbol_type *symbase;
+
+ if (!NAME(aout,slurp_symbol_table)(abfd)) return 0;
+
+ 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
+DEFUN(NAME(aout,swap_std_reloc_out),(abfd, g, natptr),
+ bfd *abfd AND
+ arelent *g AND
+ 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;
+ unsigned int r_addend;
+ 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, r_relative??? FIXME-soon */
+ r_jmptable = 0;
+ r_relative = 0;
+
+ r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
+
+ /* 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)
+ || output_section == &bfd_abs_section
+ || output_section == &bfd_und_section)
+ {
+ if (bfd_abs_section.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
+DEFUN(NAME(aout,swap_ext_reloc_out),(abfd, g, natptr),
+ bfd *abfd AND
+ arelent *g AND
+ 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)
+ || output_section == &bfd_abs_section
+ || output_section == &bfd_und_section)
+ {
+ if (bfd_abs_section.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.symbol_ptr_ptr; \
+ cache_ptr->addend = ad; \
+ break; \
+ } \
+ } \
+
+void
+DEFUN(NAME(aout,swap_ext_reloc_in), (abfd, bytes, cache_ptr, symbols),
+ bfd *abfd AND
+ struct reloc_ext_external *bytes AND
+ arelent *cache_ptr AND
+ 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
+DEFUN(NAME(aout,swap_std_reloc_in), (abfd, bytes, cache_ptr, symbols),
+ bfd *abfd AND
+ struct reloc_std_external *bytes AND
+ arelent *cache_ptr AND
+ 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;
+ BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std));
+ cache_ptr->howto = howto_table_std + howto_idx;
+ BFD_ASSERT (cache_ptr->howto->type != -1);
+ BFD_ASSERT (r_jmptable == 0);
+ BFD_ASSERT (r_relative == 0);
+ /* FIXME-soon: Roll jmptable, relative bits into howto setting */
+
+ MOVE_ADDRESS(0);
+}
+
+/* Reloc hackery */
+
+boolean
+DEFUN(NAME(aout,slurp_reloc_table),(abfd, asect, symbols),
+ bfd *abfd AND
+ sec_ptr asect AND
+ asymbol **symbols)
+{
+ unsigned int count;
+ bfd_size_type reloc_size;
+ PTR relocs;
+ arelent *reloc_cache;
+ size_t each_size;
+
+ if (asect->relocation) return true;
+
+ if (asect->flags & SEC_CONSTRUCTOR) return true;
+
+ if (asect == obj_datasec (abfd)) {
+ reloc_size = exec_hdr(abfd)->a_drsize;
+ goto doit;
+ }
+
+ if (asect == obj_textsec (abfd)) {
+ reloc_size = exec_hdr(abfd)->a_trsize;
+ goto doit;
+ }
+
+ bfd_error = invalid_operation;
+ return false;
+
+ doit:
+ bfd_seek (abfd, asect->rel_filepos, SEEK_SET);
+ each_size = obj_reloc_entry_size (abfd);
+
+ count = reloc_size / each_size;
+
+
+ reloc_cache = (arelent *) bfd_zalloc (abfd, (size_t)(count * sizeof
+ (arelent)));
+ if (!reloc_cache) {
+nomem:
+ bfd_error = no_memory;
+ return false;
+ }
+
+ relocs = (PTR) bfd_alloc (abfd, reloc_size);
+ if (!relocs) {
+ bfd_release (abfd, reloc_cache);
+ goto nomem;
+ }
+
+ if (bfd_read (relocs, 1, reloc_size, abfd) != reloc_size) {
+ bfd_release (abfd, relocs);
+ bfd_release (abfd, reloc_cache);
+ bfd_error = system_call_error;
+ return false;
+ }
+
+ if (each_size == RELOC_EXT_SIZE) {
+ register struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
+ unsigned int counter = 0;
+ arelent *cache_ptr = reloc_cache;
+
+ 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;
+ unsigned int counter = 0;
+ arelent *cache_ptr = reloc_cache;
+
+ for (; counter < count; counter++, rptr++, cache_ptr++) {
+ NAME(aout,swap_std_reloc_in)(abfd, rptr, cache_ptr, symbols);
+ }
+
+ }
+
+ bfd_release (abfd,relocs);
+ asect->relocation = reloc_cache;
+ asect->reloc_count = count;
+ return true;
+}
+
+
+
+/* Write out a relocation section into an object file. */
+
+boolean
+DEFUN(NAME(aout,squirt_out_relocs),(abfd, section),
+ bfd *abfd AND
+ 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_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)
+ NAME(aout,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 */
+unsigned int
+DEFUN(NAME(aout,canonicalize_reloc),(abfd, section, relptr, symbols),
+ bfd *abfd AND
+ sec_ptr section AND
+ arelent **relptr AND
+ asymbol **symbols)
+{
+ arelent *tblptr = section->relocation;
+ unsigned int count;
+
+ if (!(tblptr || NAME(aout,slurp_reloc_table)(abfd, section, symbols)))
+ return 0;
+
+ 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;
+ if (!tblptr) return 0;
+
+ for (count = 0; count++ < section->reloc_count;)
+ {
+ *relptr++ = tblptr++;
+ }
+ }
+ *relptr = 0;
+
+ return section->reloc_count;
+}
+
+unsigned int
+DEFUN(NAME(aout,get_reloc_upper_bound),(abfd, asect),
+ bfd *abfd AND
+ sec_ptr asect)
+{
+ if (bfd_get_format (abfd) != bfd_object) {
+ bfd_error = invalid_operation;
+ return 0;
+ }
+ 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));
+
+ bfd_error = invalid_operation;
+ return 0;
+}
+
+
+ unsigned int
+DEFUN(NAME(aout,get_symtab_upper_bound),(abfd),
+ bfd *abfd)
+{
+ if (!NAME(aout,slurp_symbol_table)(abfd)) return 0;
+
+ return (bfd_get_symcount (abfd)+1) * (sizeof (aout_symbol_type *));
+}
+ alent *
+DEFUN(NAME(aout,get_lineno),(ignore_abfd, ignore_symbol),
+ bfd *ignore_abfd AND
+ asymbol *ignore_symbol)
+{
+return (alent *)NULL;
+}
+
+void
+DEFUN(NAME(aout,get_symbol_info),(ignore_abfd, symbol, ret),
+ bfd *ignore_abfd AND
+ asymbol *symbol AND
+ 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;
+ }
+}
+
+void
+DEFUN(NAME(aout,print_symbol),(ignore_abfd, afile, symbol, how),
+ bfd *ignore_abfd AND
+ PTR afile AND
+ asymbol *symbol AND
+ 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
+DEFUN(NAME(aout,find_nearest_line),(abfd,
+ section,
+ symbols,
+ offset,
+ filename_ptr,
+ functionname_ptr,
+ line_ptr),
+ bfd *abfd AND
+ asection *section AND
+ asymbol **symbols AND
+ bfd_vma offset AND
+ CONST char **filename_ptr AND
+ CONST char **functionname_ptr AND
+ 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;
+ strncpy(buffer, function, sizeof(buffer)-1);
+ 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;
+
+}
+
+int
+DEFUN(NAME(aout,sizeof_headers),(abfd, execable),
+ bfd *abfd AND
+ boolean execable)
+{
+ return adata(abfd).exec_bytes_size;
+}
diff --git a/gnu/usr.bin/gdb/bfd/archive.c b/gnu/usr.bin/gdb/bfd/archive.c
new file mode 100644
index 0000000..5edae9d
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/archive.c
@@ -0,0 +1,1770 @@
+/* BFD back-end for archive files (libraries).
+ Copyright 1990, 1991, 1992, 1993 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
+ Archives are supported in BFD in <<archive.c>>.
+
+ 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 considered its contents. These BFDs can be
+ manipulated just 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; it will be handled correctly when the archive is closed.
+
+ Use <<bfd_openr_next_archived_file>> to step through all
+ the contents of an archive opened for input. It's not
+ required that you 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
+ <<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; Sun 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 due to restrctions 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.
+*/
+
+/* 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 current 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/*.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)
+
+/* Forward declarations of functions */
+
+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_error = no_memory;
+ return false;
+ }
+ bfd_ardata(abfd)->cache = 0;
+ return true;
+}
+
+/*
+FUNCTION
+ bfd_get_next_mapent
+
+SYNOPSIS
+ symindex bfd_get_next_mapent(bfd *, symindex previous, carsym ** sym);
+
+DESCRIPTION
+ This function steps through an archive's symbol table (if it
+ has one). Successively updates <<sym>> with the next symbol's
+ information, returning that symbol's (internal) index into the
+ symbol table.
+
+ Supply BFD_NO_MORE_SYMBOLS as the <<previous>> entry to get
+ the first one; returns BFD_NO_MORE_SYMBOLS when you're 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
+DEFUN(bfd_get_next_mapent,(abfd, prev, entry),
+ bfd *abfd AND
+ symindex prev AND
+ carsym **entry)
+{
+ if (!bfd_has_map (abfd)) {
+ 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 = new_bfd_contained_in(obfd);
+ if (nbfd == NULL)
+ {
+ 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
+ Used whilst processing archives. Sets the head of the chain of
+ BFDs contained in an archive to @var{new_head}.
+*/
+
+boolean
+DEFUN(bfd_set_archive_head,(output_archive, new_head),
+ bfd *output_archive AND
+ bfd *new_head)
+{
+
+ output_archive->archive_head = new_head;
+ return true;
+}
+
+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
+add_bfd_to_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_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;
+
+ for (; 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. */
+char *
+get_extended_arelt_filename (arch, name)
+ bfd *arch;
+ 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_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 *
+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)) {
+ bfd_error = no_more_archived_files;
+ return NULL;
+ }
+ if (strncmp ((hdr.ar_fmag), ARFMAG, 2)) {
+ bfd_error = malformed_archive;
+ return NULL;
+ }
+
+ errno = 0;
+ parsed_size = strtol (hdr.ar_size, NULL, 10);
+ if (errno != 0) {
+ 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_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_error = no_memory;
+ return NULL;
+ }
+ filename = allocptr
+ + (sizeof (struct areltdata) + sizeof (struct ar_hdr));
+ if (bfd_read (filename, 1, namelen, abfd) != namelen) {
+ 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_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 *
+get_elt_at_filepos (archive, filepos)
+ bfd *archive;
+ file_ptr filepos;
+{
+ struct areltdata *new_areldata;
+ bfd *n_nfd;
+
+ n_nfd = look_for_bfd_in_cache (archive, filepos);
+ if (n_nfd)
+ return n_nfd;
+
+ if (0 > bfd_seek (archive, filepos, SEEK_SET))
+ {
+ bfd_error = system_call_error;
+ return NULL;
+ }
+
+ if ((new_areldata = 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 (add_bfd_to_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 indexed by <<index>>.
+ <<index>> should have been returned by <<bfd_get_next_mapent>> (q.v.).
+
+*/
+bfd *
+DEFUN(bfd_get_elt_at_index,(abfd, index),
+ bfd *abfd AND
+ int index)
+{
+ bfd *result =
+ get_elt_at_filepos
+ (abfd, (bfd_ardata (abfd)->symdefs + index)->file_offset);
+ return result;
+}
+
+/*
+FUNCTION
+ bfd_openr_next_archived_file
+
+SYNOPSIS
+ bfd* bfd_openr_next_archived_file(bfd *archive, bfd *previous);
+
+DESCRIPTION
+ Initially provided a BFD containing an archive and NULL, opens
+ an inpout BFD on the first contained element and returns that.
+ Subsequent calls to bfd_openr_next_archived_file 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_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 get_elt_at_filepos (archive, filestart);
+}
+
+
+bfd_target *
+bfd_generic_archive_p (abfd)
+ bfd *abfd;
+{
+ char armag[SARMAG+1];
+
+ if (bfd_read ((PTR)armag, 1, SARMAG, abfd) != SARMAG) {
+ bfd_error = wrong_format;
+ return 0;
+ }
+
+#ifdef GNU960
+ if (strncmp (armag, BFD_GNU960_ARMAG(abfd), SARMAG)) return 0;
+#else
+ if (strncmp (armag, ARMAG, SARMAG) &&
+ strncmp (armag, ARMAGB, SARMAG)) 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_error = no_memory;
+ return 0;
+ }
+
+ bfd_ardata (abfd)->first_file_filepos = SARMAG;
+
+ if (!BFD_SEND (abfd, _bfd_slurp_armap, (abfd))) {
+ bfd_release(abfd, bfd_ardata (abfd));
+ abfd->tdata.aout_ar_data = NULL;
+ return 0;
+ }
+
+ if (!BFD_SEND (abfd, _bfd_slurp_extended_name_table, (abfd))) {
+ bfd_release(abfd, bfd_ardata (abfd));
+ abfd->tdata.aout_ar_data = NULL;
+ return 0;
+ }
+
+ return abfd->xvec;
+}
+
+/* Returns false on error, true otherwise */
+static boolean
+DEFUN (do_slurp_bsd_armap, (abfd),
+ bfd *abfd)
+{
+ struct areltdata *mapdata;
+ unsigned int counter = 0;
+ int *raw_armap, *rbase;
+ struct artdata *ardata = bfd_ardata (abfd);
+ char *stringbase;
+ unsigned int parsed_size;
+
+ mapdata = 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 = (int *) bfd_zalloc(abfd, parsed_size);
+ if (raw_armap == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ if (bfd_read ((PTR)raw_armap, 1, parsed_size, abfd) != parsed_size) {
+ bfd_error = malformed_archive;
+ byebye:
+ bfd_release (abfd, (PTR)raw_armap);
+ return false;
+ }
+
+ ardata->symdef_count =
+ bfd_h_get_32(abfd, (PTR)raw_armap) / sizeof (struct symdef);
+
+ if (ardata->symdef_count * sizeof (struct symdef)
+ > parsed_size - sizeof (*raw_armap)) {
+ /* Probably we're using the wrong byte ordering. */
+ bfd_error = wrong_format;
+ goto byebye;
+ }
+
+ ardata->cache = 0;
+ rbase = raw_armap+1;
+ ardata->symdefs = (carsym *) rbase;
+ stringbase = ((char *) (ardata->symdefs + ardata->symdef_count)) + 4;
+
+ for (;counter < ardata->symdef_count; counter++) {
+ struct symdef *sym = ((struct symdef *) rbase) + counter;
+ sym->s.name = bfd_h_get_32(abfd, (PTR)(&(sym->s.string_offset))) + stringbase;
+ sym->file_offset = bfd_h_get_32(abfd, (PTR)( &(sym->file_offset)));
+ }
+
+ 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
+DEFUN (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 ((bfd_byte*));
+ char int_buf[sizeof(long)];
+ unsigned int carsym_size, ptrsize, i;
+
+ mapdata = 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) {
+ 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_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_error = no_memory;
+ goto release_symdefs;
+ }
+ if (bfd_read ((PTR)raw_armap, 1, ptrsize, abfd) != ptrsize
+ || bfd_read ((PTR)stringbase, 1, stringsize, abfd) != stringsize) {
+ 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;
+ while (*stringbase++) ;
+ 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;
+
+ bfd_seek (abfd, (file_ptr) -16, SEEK_CUR);
+
+ if (!strncmp (nextname, "__.SYMDEF ", 16))
+ 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. */
+boolean
+bfd_slurp_bsd_armap_f2 (abfd)
+ bfd *abfd;
+{
+ struct areltdata *mapdata;
+ char nextname[17];
+ unsigned int counter = 0;
+ int *raw_armap, *rbase;
+ struct artdata *ardata = bfd_ardata (abfd);
+ char *stringbase;
+ unsigned int stringsize;
+ 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 */
+ bfd_seek (abfd, -16L, SEEK_CUR);
+
+ if (!strncmp (nextname, "__.SYMDEF ", 16))
+ return do_slurp_bsd_armap (abfd);
+
+ if (strncmp (nextname, "/ ", 16))
+ {
+ bfd_has_map (abfd) = false;
+ return true;
+ }
+
+ mapdata = snarf_ar_hdr (abfd);
+ if (mapdata == NULL) return false;
+
+ raw_armap = (int *) bfd_zalloc(abfd,mapdata->parsed_size);
+ if (raw_armap == NULL)
+ {
+ 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)
+ {
+ 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 * sizeof (struct symdef)
+ > mapdata->parsed_size - sizeof (*raw_armap))
+ {
+ /* Probably we're using the wrong byte ordering. */
+ bfd_error = wrong_format;
+ goto byebyebye;
+ }
+
+ ardata->cache = 0;
+
+ stringsize = bfd_h_get_32(abfd, (PTR)(((char*)raw_armap)+2));
+ /* skip sym count and string sz */
+ rbase = (int*)(((char*)raw_armap) + 6);
+ stringbase = (char *) rbase;
+ ardata->symdefs = (carsym *)(((char*) rbase) + stringsize);
+
+ for (;counter < ardata->symdef_count; counter++)
+ {
+ struct symdef *sym = ((struct symdef *) ardata->symdefs) + counter;
+ sym->s.name = bfd_h_get_32(abfd, (PTR)(&(sym->s.string_offset))) + stringbase;
+ sym->file_offset = bfd_h_get_32(abfd, (PTR)( &(sym->file_offset)));
+ }
+
+ 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) {
+
+ bfd_seek (abfd, (file_ptr) -16, SEEK_CUR);
+
+ if (strncmp (nextname, "ARFILENAMES/ ", 16) != 0 &&
+ strncmp (nextname, "// ", 16) != 0)
+ {
+ bfd_ardata (abfd)->extended_names = NULL;
+ return true;
+ }
+
+ namedata = 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_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) {
+ 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 == '\n')
+ 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 *
+DEFUN(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 = bfd_xmalloc(last - first + 1);
+ memcpy(copy, first, last-first);
+ copy[last-first] = 0;
+
+ return copy;
+}
+
+#else
+static CONST char *
+DEFUN (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!
+ */
+boolean
+DEFUN (bfd_construct_extended_name_table, (abfd, tabloc, tablen),
+ bfd *abfd AND
+ char **tabloc AND
+ 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){
+ unsigned int thislen = strlen (normalize(current->filename));
+ 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_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 = 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] = '\n';
+ hdr->ar_name[0] = ' ';
+ /* 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
+*/
+
+struct areltdata *
+DEFUN(bfd_ar_hdr_from_filesystem, (abfd,filename),
+ bfd* abfd AND
+ CONST char *filename)
+{
+ struct stat status;
+ struct areltdata *ared;
+ struct ar_hdr *hdr;
+ char *temp, *temp1;
+
+
+ if (stat (filename, &status) != 0) {
+ bfd_error = system_call_error;
+ return NULL;
+ }
+
+ ared = (struct areltdata *) bfd_zalloc(abfd, sizeof (struct ar_hdr) +
+ sizeof (struct areltdata));
+ if (ared == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+ hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata));
+
+ /* ar headers are space padded, not null padded! */
+ temp = (char *) hdr;
+ temp1 = temp + sizeof (struct ar_hdr) - 2;
+ for (; temp < temp1; *(temp++) = ' ');
+ strncpy (hdr->ar_fmag, ARFMAG, 2);
+
+ /* Goddamned sprintf doesn't permit MAXIMUM field lengths */
+ sprintf ((hdr->ar_date), "%-12ld", status.st_mtime);
+ sprintf ((hdr->ar_uid), "%d", status.st_uid);
+ sprintf ((hdr->ar_gid), "%d", status.st_gid);
+ sprintf ((hdr->ar_mode), "%-8o", (unsigned) status.st_mode);
+ sprintf ((hdr->ar_size), "%-10ld", 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 *
+DEFUN(bfd_special_undocumented_glue, (abfd, filename),
+ bfd *abfd AND
+ 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_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);
+ return;
+
+}
+
+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 */
+ 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_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) { /* 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;
+
+ bfd_seek (arch, (file_ptr) 0, SEEK_SET);
+#ifdef GNU960
+ bfd_write (BFD_GNU960_ARMAG(arch), 1, SARMAG, arch);
+#else
+ bfd_write (ARMAG, 1, SARMAG, arch);
+#endif
+
+ 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));
+ sprintf (&(hdr.ar_name[0]), "ARFILENAMES/");
+ sprintf (&(hdr.ar_size[0]), "%-10d", (int) elength);
+ hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n';
+ for (i = 0; i < sizeof (struct ar_hdr); i++)
+ if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' ';
+ bfd_write ((char *)&hdr, 1, sizeof (struct ar_hdr), arch);
+ bfd_write (etable, 1, elength, arch);
+ if ((elength % 2) == 1) bfd_write ("\n", 1, 1, arch);
+
+ }
+
+ 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)) {
+ syserr:
+ bfd_error = system_call_error;
+ return false;
+ }
+ if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0) goto syserr;
+ while (remaining)
+ {
+ unsigned int amt = DEFAULT_BUFFERSIZE;
+ if (amt > remaining) {
+ amt = remaining;
+ }
+ errno = 0;
+ if (bfd_read (buffer, amt, 1, current) != amt) {
+ if (errno) goto syserr;
+ /* Looks like a truncated archive. */
+ bfd_error = malformed_archive;
+ return false;
+ }
+ if (bfd_write (buffer, amt, 1, arch) != amt) goto syserr;
+ remaining -= amt;
+ }
+ if ((arelt_size (current) % 2) == 1) bfd_write ("\n", 1, 1, arch);
+ }
+
+ /* 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 */
+
+boolean
+compute_and_write_armap (arch, elength)
+ bfd *arch;
+ unsigned int elength;
+{
+ bfd *current;
+ file_ptr elt_no = 0;
+ struct orl *map;
+ int orl_max = 15000; /* fine initial default */
+ int orl_count = 0;
+ int stridx = 0; /* string index */
+
+ /* Dunno if this is the best place for this info... */
+ if (elength != 0) elength += sizeof (struct ar_hdr);
+ elength += elength %2 ;
+
+ map = (struct orl *) bfd_zalloc (arch,orl_max * sizeof (struct orl));
+ if (map == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ /* 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))) {
+ asymbol **syms;
+ unsigned int storage;
+ unsigned int symcount;
+ unsigned int src_count;
+
+ storage = get_symtab_upper_bound (current);
+ if (storage != 0) {
+
+ syms = (asymbol **) bfd_zalloc (arch,storage);
+ if (syms == NULL) {
+ bfd_error = no_memory; /* FIXME -- memory leak */
+ return false;
+ }
+ symcount = bfd_canonicalize_symtab (current, syms);
+
+
+ /* 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))
+ && (sec != &bfd_und_section)) {
+
+ /* This symbol will go into the archive header */
+ if (orl_count == orl_max)
+ {
+ orl_max *= 2;
+ map = (struct orl *) bfd_realloc (arch, (char *) map,
+ orl_max * sizeof (struct orl));
+ }
+
+ (map[orl_count]).name = (char **) &((syms[src_count])->name);
+ (map[orl_count]).pos = (file_ptr) current;
+ (map[orl_count]).namidx = stridx;
+
+ stridx += strlen ((syms[src_count])->name) + 1;
+ ++orl_count;
+ }
+ }
+ }
+ }
+ }
+ /* OK, now we have collected all the data, let's write them out */
+ if (!BFD_SEND (arch, write_armap,
+ (arch, elength, map, orl_count, stridx))) {
+
+ return false;
+ }
+
+
+ return true;
+}
+
+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);
+ hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n';
+ for (i = 0; i < sizeof (struct ar_hdr); i++)
+ if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' ';
+ bfd_write ((char *)&hdr, 1, sizeof (struct ar_hdr), arch);
+ bfd_h_put_32(arch, (bfd_vma) ranlibsize, (PTR)&temp);
+ bfd_write (&temp, 1, sizeof (temp), arch);
+
+ 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);
+ bfd_write ((char *)outp, 1, sizeof (outs), arch);
+ }
+
+ /* now write the strings themselves */
+ bfd_h_put_32(arch, stringsize, (PTR)&temp);
+ bfd_write ((PTR)&temp, 1, sizeof (temp), arch);
+ for (count = 0; count < orl_count; count++)
+ bfd_write (*((map[count]).name), 1, strlen (*((map[count]).name))+1, arch);
+
+ /* 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)
+ bfd_write("\0",1,1,arch);
+
+ 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. */
+ bfd_seek (arch, bfd_ardata(arch)->armap_datepos, SEEK_SET);
+ if (bfd_write (hdr.ar_date, sizeof(hdr.ar_date), 1, arch)
+ != sizeof(hdr.ar_date)) {
+ 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);
+ hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n';
+
+ 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 */
+
+
+ bfd_write ((PTR)&hdr, 1, sizeof (struct ar_hdr), arch);
+
+ 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++) {
+ bfd_write ((PTR)*((map[count]).name),
+ 1,
+ strlen (*((map[count]).name))+1, arch);
+
+ }
+ /* The spec sez this should be a newline. But in order to be
+ bug-compatible for arc960 we use a null. */
+ if (padit)
+ bfd_write("\0",1,1,arch);
+
+ 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..9697904
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/archures.c
@@ -0,0 +1,731 @@
+/* BFD library support routines for architectures.
+ Copyright (C) 1990-1991 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's idea of an architecture is implimented in
+ <<archures.c>>. 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 arch information is provided by each architecture package.
+ The set of default architectures is selected by the #define
+ <<SELECT_ARCHITECTURES>>. This is normally set up in the
+ <<config/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).
+*/
+
+/*
+
+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?
+ There is another field, which indicates what processor within
+ the family is in use. The machine gives a number which
+ distingushes 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_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_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 arch info structure
+
+*/
+
+CONST char *
+DEFUN(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 *);
+
+DESCRIPTION
+ This routine is provided with a string and tries to work out
+ if bfd supports any cpu which could be described with the name
+ provided. The routine returns a pointer to an arch_info
+ structure if a machine is found, otherwise NULL.
+
+*/
+
+bfd_arch_info_type *
+DEFUN(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
+ This routine is used to determine whether two BFDs'
+ architectures and achine types are compatible. It 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 *
+DEFUN(bfd_arch_get_compatible,(abfd, bbfd),
+CONST bfd *abfd AND
+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 *, bfd_arch_info_type *);
+
+*/
+
+void DEFUN(bfd_set_arch_info,(abfd, arg),
+bfd *abfd AND
+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 a bfd. This finds the
+ correct pointer to structure and inserts it into the arch_info
+ pointer.
+*/
+
+boolean DEFUN(bfd_default_set_arch_mach,(abfd, arch, mach),
+ bfd *abfd AND
+ enum bfd_architecture arch AND
+ 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_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
+ Returns the enumerated type which describes the supplied bfd's
+ architecture
+
+*/
+
+enum bfd_architecture DEFUN(bfd_get_arch, (abfd), bfd *abfd)
+{
+ return abfd->arch_info->arch;
+}
+
+/*
+FUNCTION
+ bfd_get_mach
+
+SYNOPSIS
+ unsigned long bfd_get_mach(bfd *abfd);
+
+DESCRIPTION
+ Returns the long type which describes the supplied bfd's
+ machine
+*/
+
+unsigned long
+DEFUN(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
+ Returns the number of bits in one of the architectures bytes
+
+*/
+
+unsigned int DEFUN(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
+ Returns the number of bits in one of the architectures addresses
+*/
+
+unsigned int DEFUN(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_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));
+
+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_rs6000_arch,
+ bfd_sh_arch,
+ bfd_sparc_arch,
+ bfd_vax_arch,
+ bfd_we32k_arch,
+ bfd_z8k_arch,
+#endif
+ 0
+ };
+
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_arch_init
+
+SYNOPSIS
+ void bfd_arch_init(void);
+
+DESCRIPTION
+ This routine initializes the architecture dispatch table by
+ calling all installed architecture packages and getting them
+ to poke around.
+*/
+
+void
+DEFUN_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 *);
+
+DESCRIPTION
+ Link the provided arch info structure into the list
+*/
+
+void DEFUN(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 *
+DEFUN(bfd_default_compatible,(a,b),
+ CONST bfd_arch_info_type *a AND
+ 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 *, CONST char *);
+
+DESCRIPTION
+ The default function for working out whether this is an
+ architecture hit and a machine hit.
+*/
+
+boolean
+DEFUN(bfd_default_scan,(info, string),
+CONST struct bfd_arch_info *info AND
+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 *);
+
+*/
+
+bfd_arch_info_type *
+DEFUN(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 struct which matches the
+ arguments given. A machine of 0 will match the
+ machine/architecture structure which marks itself as the
+ default.
+*/
+
+bfd_arch_info_type *
+DEFUN(bfd_lookup_arch,(arch, machine),
+enum bfd_architecture arch AND
+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.
+
+ NB. The use of this routine is depreciated.
+*/
+
+CONST char *
+DEFUN(bfd_printable_arch_mach,(arch, machine),
+ enum bfd_architecture arch AND
+ 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..a994cd1
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/bfd.c
@@ -0,0 +1,733 @@
+/* Generic BFD library interface and support routines.
+ 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
+ <<typedef bfd>>
+
+ A BFD is has type <<bfd>>; objects of this type are the
+ cornerstone of any application using <<libbfd>>. References
+ though the BFD and to data in the BFD give the entire BFD
+ functionality.
+
+ Here is the struct used to define the type <<bfd>>. This
+ contains the major data about the file, and contains 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. *}
+. 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 being cached *}
+.
+. boolean cacheable;
+.
+. {* Marks whether there was a default target specified when the
+. BFD was opened. This is used to select what matching algorithm
+. to use to chose 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:*}
+.
+. 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.*}
+.
+. 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
+. 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*}
+. 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;
+. struct _bfd *next;
+. struct _bfd *archive_head;
+. boolean has_armap;
+.
+. {* 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 hppa_data_struct *hppa_data;
+. struct hpux_core_struct *hpux_core_data;
+. struct sgi_core_struct *sgi_core_data;
+. struct lynx_core_struct *lynx_core_data;
+. struct osf_core_struct *osf_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;
+.
+. {* Is this really needed in addition to usrdata? *}
+. asymbol **ld_symbols;
+.};
+.
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "coff/internal.h"
+#include "coff/sym.h"
+#include "libcoff.h"
+#include "libecoff.h"
+#undef obj_symbols
+#include "libelf.h"
+
+#undef strerror
+extern char *strerror();
+
+/** Error handling
+ o - Most functions return nonzero on success (check doc for
+ precise semantics); 0 or NULL on error.
+ o - Internal errors are documented by the value of bfd_error.
+ If that is system_call_error then check errno.
+ o - The easiest way to report this to the user is to use bfd_perror.
+*/
+
+bfd_ec bfd_error = no_error;
+
+CONST char *CONST bfd_errmsgs[] = {
+ "No error",
+ "System call error",
+ "Invalid target",
+ "File in wrong format",
+ "Invalid operation",
+ "Memory exhausted",
+ "No symbols",
+ "No relocation info",
+ "No more archived files",
+ "Malformed archive",
+ "Symbol not found",
+ "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>"
+ };
+
+static
+void
+DEFUN(bfd_nonrepresentable_section,(abfd, name),
+ CONST bfd * CONST abfd AND
+ CONST char * CONST name)
+{
+ fprintf(stderr,
+ "bfd error writing file %s, format %s can't represent section %s\n",
+ abfd->filename,
+ abfd->xvec->name,
+ name);
+ exit(1);
+}
+
+/*ARGSUSED*/
+static
+void
+DEFUN(bfd_undefined_symbol,(relent, seclet),
+ CONST arelent *relent AND
+ CONST struct bfd_seclet *seclet)
+{
+ asymbol *symbol = *(relent->sym_ptr_ptr);
+ fprintf(stderr, "bfd error relocating, symbol %s is undefined\n",
+ symbol->name);
+ exit(1);
+}
+/*ARGSUSED*/
+static
+void
+DEFUN(bfd_reloc_value_truncated,(relent, seclet),
+ CONST arelent *relent AND
+ struct bfd_seclet *seclet)
+{
+ fprintf(stderr, "bfd error relocating, value truncated\n");
+ exit(1);
+}
+/*ARGSUSED*/
+static
+void
+DEFUN(bfd_reloc_is_dangerous,(relent, seclet),
+ CONST arelent *relent AND
+ CONST struct bfd_seclet *seclet)
+{
+ fprintf(stderr, "bfd error relocating, dangerous\n");
+ exit(1);
+}
+
+bfd_error_vector_type bfd_error_vector =
+ {
+ bfd_nonrepresentable_section ,
+ bfd_undefined_symbol,
+ bfd_reloc_value_truncated,
+ bfd_reloc_is_dangerous,
+ };
+
+
+CONST char *
+bfd_errmsg (error_tag)
+ bfd_ec error_tag;
+{
+#ifndef errno
+ extern int errno;
+#endif
+ if (error_tag == system_call_error)
+ return strerror (errno);
+
+ if ((((int)error_tag <(int) no_error) ||
+ ((int)error_tag > (int)invalid_error_code)))
+ error_tag = invalid_error_code;/* sanity check */
+
+ return bfd_errmsgs [(int)error_tag];
+}
+
+void
+DEFUN (bfd_default_error_trap, (error_tag),
+ bfd_ec error_tag)
+{
+ fprintf(stderr, "bfd assert fail (%s)\n", bfd_errmsg(error_tag));
+}
+
+void (*bfd_error_trap) PARAMS ((bfd_ec)) = bfd_default_error_trap;
+void (*bfd_error_nonrepresentabltrap) PARAMS ((bfd_ec)) = bfd_default_error_trap;
+
+void
+DEFUN(bfd_perror,(message),
+ CONST char *message)
+{
+ if (bfd_error == system_call_error)
+ perror((char *)message); /* must be system error then... */
+ else {
+ if (message == NULL || *message == '\0')
+ fprintf (stderr, "%s\n", bfd_errmsg (bfd_error));
+ else
+ fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_error));
+ }
+}
+
+
+/** Symbols */
+
+
+/*
+FUNCTION
+ bfd_get_reloc_upper_bound
+
+SYNOPSIS
+ unsigned int bfd_get_reloc_upper_bound(bfd *abfd, asection *sect);
+
+DESCRIPTION
+ This function return the number of bytes required to store the
+ relocation information associated with section <<sect>>
+ attached to bfd <<abfd>>
+
+*/
+
+
+unsigned int
+DEFUN(bfd_get_reloc_upper_bound,(abfd, asect),
+ bfd *abfd AND
+ sec_ptr asect)
+{
+ if (abfd->format != bfd_object) {
+ bfd_error = invalid_operation;
+ return 0;
+ }
+
+ return BFD_SEND (abfd, _get_reloc_upper_bound, (abfd, asect));
+}
+
+/*
+FUNCTION
+ bfd_canonicalize_reloc
+
+SYNOPSIS
+ unsigned int bfd_canonicalize_reloc
+ (bfd *abfd,
+ asection *sec,
+ arelent **loc,
+ asymbol **syms);
+
+DESCRIPTION
+ This function calls the back end associated with the open
+ <<abfd>> and translates the external form of the relocation
+ information attached to <<sec>> into the internal canonical
+ form. The table is placed into memory at <<loc>>, which has
+ been preallocated, usually by a call to
+ <<bfd_get_reloc_upper_bound>>.
+
+ The <<syms>> table is also needed for horrible internal magic
+ reasons.
+
+
+*/
+unsigned int
+DEFUN(bfd_canonicalize_reloc,(abfd, asect, location, symbols),
+ bfd *abfd AND
+ sec_ptr asect AND
+ arelent **location AND
+ asymbol **symbols)
+{
+ if (abfd->format != bfd_object) {
+ bfd_error = invalid_operation;
+ return 0;
+ }
+ return BFD_SEND (abfd, _bfd_canonicalize_reloc,
+ (abfd, asect, location, symbols));
+ }
+
+
+/*
+FUNCTION
+ bfd_set_file_flags
+
+SYNOPSIS
+ boolean bfd_set_file_flags(bfd *abfd, flagword flags);
+
+DESCRIPTION
+ This function attempts to set the flag word in the referenced
+ BFD structure to the value supplied.
+
+ Possible errors are:
+ o wrong_format - The target bfd was not of object format.
+ o invalid_operation - The target bfd was open for reading.
+ o invalid_operation -
+ The flag word contained a bit which was not applicable to the
+ type of file. eg, 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_error = wrong_format;
+ return false;
+ }
+
+ if (bfd_read_p (abfd)) {
+ bfd_error = invalid_operation;
+ return false;
+ }
+
+ bfd_get_file_flags (abfd) = flags;
+ if ((flags & bfd_applicable_file_flags (abfd)) != flags) {
+ bfd_error = invalid_operation;
+ return false;
+ }
+
+return true;
+}
+
+/*
+FUNCTION
+ bfd_set_reloc
+
+SYNOPSIS
+ void bfd_set_reloc
+ (bfd *abfd, asection *sec, arelent **rel, unsigned int count)
+
+DESCRIPTION
+ This function sets the relocation pointer and count within a
+ section to the supplied values.
+
+*/
+/*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;
+}
+
+void
+bfd_assert(file, line)
+char *file;
+int line;
+{
+ fprintf(stderr, "bfd assertion fail %s:%d\n",file,line);
+}
+
+
+/*
+FUNCTION
+ bfd_set_start_address
+
+DESCRIPTION
+ Marks the entry point of an output BFD.
+
+RETURNS
+ Returns <<true>> on success, <<false>> otherwise.
+
+SYNOPSIS
+ boolean bfd_set_start_address(bfd *, bfd_vma);
+*/
+
+boolean
+bfd_set_start_address(abfd, vma)
+bfd *abfd;
+bfd_vma vma;
+{
+ abfd->start_address = vma;
+ return true;
+}
+
+
+/*
+FUNCTION
+ The bfd_get_mtime function
+
+SYNOPSIS
+ long bfd_get_mtime(bfd *);
+
+DESCRIPTION
+ Return file modification time (as read from file system, or
+ from 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
+ The bfd_get_size function
+
+SYNOPSIS
+ long bfd_get_size(bfd *);
+
+DESCRIPTION
+ Return file size (as read from file system) for the file
+ associated with a bfd.
+
+ Note that 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?).
+ Although 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 want to 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 allocated 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
+ The bfd_get_gp_size function
+
+SYNOPSIS
+ int bfd_get_gp_size(bfd *);
+
+DESCRIPTION
+ Get 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->xvec->flavour == bfd_target_ecoff_flavour)
+ return ecoff_data (abfd)->gp_size;
+ return 0;
+}
+
+/*
+FUNCTION
+ The bfd_set_gp_size function
+
+SYNOPSIS
+ void bfd_set_gp_size(bfd *, int);
+
+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;
+{
+ 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
+
+DESCRIPTION
+ Converts, like strtoul, a numerical expression as a
+ string into a bfd_vma integer, and returns that integer.
+ (Though without as many bells and whistles as strtoul.)
+ The expression is assumed to be unsigned (i.e. positive).
+ If given a 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.
+
+SYNOPSIS
+ bfd_vma bfd_scan_vma(CONST char *string, CONST char **end, int base);
+*/
+
+bfd_vma
+DEFUN(bfd_scan_vma,(string, end, base),
+ CONST char *string AND
+ CONST char **end AND
+ 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
+ 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, seclet, data, relocateable) \
+. BFD_SEND (abfd, _bfd_get_relocated_section_contents, (abfd, seclet, data, relocateable))
+.
+.#define bfd_relax_section(abfd, section, symbols) \
+. BFD_SEND (abfd, _bfd_relax_section, (abfd, section, symbols))
+.
+.#define bfd_seclet_link(abfd, data, relocateable) \
+. BFD_SEND (abfd, _bfd_seclet_link, (abfd, data, relocateable))
+
+*/
diff --git a/gnu/usr.bin/gdb/bfd/bfd.h b/gnu/usr.bin/gdb/bfd/bfd.h
new file mode 100644
index 0000000..fbe0f0f
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/bfd.h
@@ -0,0 +1,1803 @@
+/* Main header file for the bfd library -- portable access to object files.
+ Copyright 1990, 1991, 1992, 1993 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"
+
+#define BFD_VERSION "2.2"
+
+#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 */
+typedef enum bfd_boolean {false, true} boolean;
+
+/* 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 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. 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 (HOST_64_BIT)
+#define HOST_64_BIT long long
+typedef HOST_64_BIT int64_type;
+typedef unsigned HOST_64_BIT uint64_type;
+#endif
+
+#if !defined (uint64_type) && defined (__GNUC__)
+#define uint64_type unsigned long long
+#define int64_type long long
+#define uint64_typeLOW(x) (unsigned long)(((x) & 0xffffffff))
+#define uint64_typeHIGH(x) (unsigned long)(((x) >> 32) & 0xffffffff)
+#endif
+
+typedef unsigned HOST_64_BIT bfd_vma;
+typedef HOST_64_BIT bfd_signed_vma;
+typedef unsigned HOST_64_BIT bfd_size_type;
+typedef unsigned HOST_64_BIT symvalue;
+#define fprintf_vma(s,x) \
+ fprintf(s,"%08x%08x", uint64_typeHIGH(x), uint64_typeLOW(x))
+#define sprintf_vma(s,x) \
+ sprintf(s,"%08x%08x", uint64_typeHIGH(x), uint64_typeLOW(x))
+#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;
+
+/* Object file flag values */
+#define NO_FLAGS 0x00
+#define HAS_RELOC 0x01
+#define EXEC_P 0x02
+#define HAS_LINENO 0x04
+#define HAS_DEBUG 0x08
+#define HAS_SYMS 0x10
+#define HAS_LOCALS 0x20
+#define DYNAMIC 0x40
+#define WP_TEXT 0x80
+#define D_PAGED 0x100
+#define BFD_IS_RELAXABLE 0x200
+
+/* symbols and relocation */
+
+typedef unsigned long symindex;
+
+#define BFD_NO_MORE_SYMBOLS ((symindex) ~0)
+
+typedef enum bfd_symclass {
+ bfd_symclass_unknown = 0,
+ bfd_symclass_fcommon, /* fortran common symbols */
+ bfd_symclass_global, /* global symbol, what a surprise */
+ bfd_symclass_debugger, /* some debugger symbol */
+ bfd_symclass_undefined /* none known */
+ } symclass;
+
+
+/* general purpose part of a symbol;
+ target specific parts will be found in libcoff.h, liba.out.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)
+
+/* 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. 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;
+
+/** Error handling */
+
+typedef enum bfd_error {
+ no_error = 0, system_call_error, invalid_target,
+ wrong_format, invalid_operation, no_memory,
+ no_symbols, no_relocation_info,
+ no_more_archived_files, malformed_archive,
+ symbol_not_found, file_not_recognized,
+ file_ambiguously_recognized, no_contents,
+ bfd_error_nonrepresentable_section,
+ no_debug_section, bad_value,
+
+ /* An input file is shorter than expected. */
+ file_truncated,
+
+ invalid_error_code} bfd_ec;
+
+extern bfd_ec bfd_error;
+struct reloc_cache_entry;
+struct bfd_seclet;
+
+
+typedef struct bfd_error_vector {
+ void (* nonrepresentable_section ) PARAMS ((CONST bfd *CONST abfd,
+ CONST char *CONST name));
+ void (* undefined_symbol) PARAMS ((CONST struct reloc_cache_entry *rel,
+ CONST struct bfd_seclet *sec));
+ void (* reloc_value_truncated) PARAMS ((CONST struct
+ reloc_cache_entry *rel,
+ struct bfd_seclet *sec));
+
+ void (* reloc_dangerous) PARAMS ((CONST struct reloc_cache_entry *rel,
+ CONST struct bfd_seclet *sec));
+
+} bfd_error_vector_type;
+
+CONST char *bfd_errmsg PARAMS ((bfd_ec error_tag));
+void bfd_perror PARAMS ((CONST char *message));
+
+
+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;
+
+/* The code that implements targets can initialize a jump table with this
+ macro. It must name all its routines the same way (a prefix plus
+ the standard routine suffix), or it must #define the routines that
+ are not so named, before calling JUMP_TABLE in the initializer. */
+
+/* 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
+#ifdef __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 JUMP_TABLE(NAME)\
+CAT(NAME,_core_file_failing_command),\
+CAT(NAME,_core_file_failing_signal),\
+CAT(NAME,_core_file_matches_executable_p),\
+CAT(NAME,_slurp_armap),\
+CAT(NAME,_slurp_extended_name_table),\
+CAT(NAME,_truncate_arname),\
+CAT(NAME,_write_armap),\
+CAT(NAME,_close_and_cleanup),\
+CAT(NAME,_set_section_contents),\
+CAT(NAME,_get_section_contents),\
+CAT(NAME,_new_section_hook),\
+CAT(NAME,_get_symtab_upper_bound),\
+CAT(NAME,_get_symtab),\
+CAT(NAME,_get_reloc_upper_bound),\
+CAT(NAME,_canonicalize_reloc),\
+CAT(NAME,_make_empty_symbol),\
+CAT(NAME,_print_symbol),\
+CAT(NAME,_get_symbol_info),\
+CAT(NAME,_get_lineno),\
+CAT(NAME,_set_arch_mach),\
+CAT(NAME,_openr_next_archived_file),\
+CAT(NAME,_find_nearest_line),\
+CAT(NAME,_generic_stat_arch_elt),\
+CAT(NAME,_sizeof_headers),\
+CAT(NAME,_bfd_debug_info_start),\
+CAT(NAME,_bfd_debug_info_end),\
+CAT(NAME,_bfd_debug_info_accumulate),\
+CAT(NAME,_bfd_get_relocated_section_contents),\
+CAT(NAME,_bfd_relax_section),\
+CAT(NAME,_bfd_seclet_link),\
+CAT(NAME,_bfd_reloc_type_lookup),\
+CAT(NAME,_bfd_make_debug_symbol)
+
+#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_format(abfd) ((abfd)->format)
+#define bfd_get_target(abfd) ((abfd)->xvec->name)
+#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)
+
+/* Byte swapping routines. */
+
+bfd_vma bfd_getb64 PARAMS ((unsigned char *));
+bfd_vma bfd_getl64 PARAMS ((unsigned char *));
+bfd_signed_vma bfd_getb_signed_64 PARAMS ((unsigned char *));
+bfd_signed_vma bfd_getl_signed_64 PARAMS ((unsigned char *));
+bfd_vma bfd_getb32 PARAMS ((unsigned char *));
+bfd_vma bfd_getl32 PARAMS ((unsigned char *));
+bfd_signed_vma bfd_getb_signed_32 PARAMS ((unsigned char *));
+bfd_signed_vma bfd_getl_signed_32 PARAMS ((unsigned char *));
+bfd_vma bfd_getb16 PARAMS ((unsigned char *));
+bfd_vma bfd_getl16 PARAMS ((unsigned char *));
+bfd_signed_vma bfd_getb_signed_16 PARAMS ((unsigned char *));
+bfd_signed_vma bfd_getl_signed_16 PARAMS ((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 *));
+
+/* 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 *));
+
+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 of
+ 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 loaded.
+ This would 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 would be clear for a .bss section */
+#define SEC_LOAD 0x002
+
+ /* The section contains data still to be relocated, so there will
+ be 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 (eg <<__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 relocte 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 not to output sections
+ containing this flag even if they have information which
+ would normally be written. */
+#define SEC_NEVER_LOAD 0x400
+
+ /* The section is a shared library section. The linker must leave
+ these completely alone, as the vma and size are used when
+ the executable is loaded. */
+#define SEC_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), 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
+
+ /* 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 (eg, the
+ size of <<.bss>>). This will be filled in after relocation */
+
+ bfd_size_type _cooked_size;
+
+ /* The size on disk of the section in bytes originally. 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. Eg, 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 - eg
+ 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;
+
+ struct lang_output_section *otheruserdata;
+
+ /* 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_seclet *seclets_head;
+ struct bfd_seclet *seclets_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. */
+#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 asection bfd_abs_section;
+ /* Pointer to the undefined section */
+extern asection bfd_und_section;
+ /* Pointer to the common section */
+extern asection bfd_com_section;
+ /* Pointer to the indirect section */
+extern asection bfd_ind_section;
+
+extern struct symbol_cache_entry *bfd_abs_symbol;
+extern struct symbol_cache_entry *bfd_com_symbol;
+extern struct symbol_cache_entry *bfd_und_symbol;
+extern struct symbol_cache_entry *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 *, CONST char *name));
+
+asection *
+bfd_make_section_anyway PARAMS ((bfd *, CONST char *name));
+
+asection *
+bfd_make_section PARAMS ((bfd *, CONST char *name));
+
+boolean
+bfd_set_section_flags PARAMS ((bfd *, asection *, flagword));
+
+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 *, asection *, 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));
+
+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_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_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 *));
+
+CONST bfd_arch_info_type *
+bfd_arch_get_compatible PARAMS ((
+ CONST bfd *abfd,
+ CONST bfd *bbfd));
+
+void
+bfd_set_arch_info PARAMS ((bfd *, bfd_arch_info_type *));
+
+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 *));
+
+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,
+
+ /* Unused */
+ bfd_reloc_notsupported,
+
+ /* Unsupported relocation size requested. */
+ 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. */
+ 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 CONST struct reloc_howto_struct
+{
+ /* The type field has mainly a documetary use - the back end can
+ to what it wants with it, though the normally the back end's
+ external idea of what a reloc number would be would be stored
+ in this field. For example, the a PC relative word relocation
+ in a coff environment would have 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.
+ 0 : one byte
+ 1 : two bytes
+ 2 : four bytes
+ 3 : nothing done (unless special_function is nonzero)
+ 4 : eight bytes
+ -2 : two bytes, result should be subtracted from the
+ data instead of added
+ There is currently no trivial way to extract a "number of
+ bytes" from a howto pointer. */
+ 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));
+
+ /* 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 is used to select what 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 is what 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;
+
+} reloc_howto_type;
+#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; \
+ } \
+ } \
+}
+typedef unsigned char bfd_byte;
+
+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));
+
+typedef enum bfd_reloc_code_real
+{
+ /* Basic absolute relocations */
+ BFD_RELOC_64,
+ BFD_RELOC_32,
+ BFD_RELOC_16,
+ 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,
+
+ /* 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,
+
+ /* 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,
+
+
+ /* Bits 27..2 of the relocation address shifted right 2 bits;
+ simple reloc otherwise. */
+ BFD_RELOC_MIPS_JMP,
+
+ /* signed 16-bit pc-relative, shifted right 2 bits (e.g. for MIPS) */
+ BFD_RELOC_16_PCREL_S2,
+
+ /* 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,
+
+ /* 16 bit relocation relative to the global pointer. */
+ BFD_RELOC_MIPS_GPREL,
+
+ /* These are, so far, specific to HPPA processors. I'm not sure that some
+ don't duplicate other reloc types, such as BFD_RELOC_32 and _32_PCREL.
+ Also, many more were in the list I got that don't fit in well in the
+ model BFD uses, so I've omitted them for now. If we do make this reloc
+ type get used for code that really does implement the funky reloc types,
+ they'll have to be added to this list. */
+ BFD_RELOC_HPPA_32,
+ BFD_RELOC_HPPA_11,
+ BFD_RELOC_HPPA_14,
+ BFD_RELOC_HPPA_17,
+
+ BFD_RELOC_HPPA_L21,
+ BFD_RELOC_HPPA_R11,
+ BFD_RELOC_HPPA_R14,
+ BFD_RELOC_HPPA_R17,
+ BFD_RELOC_HPPA_LS21,
+ BFD_RELOC_HPPA_RS11,
+ BFD_RELOC_HPPA_RS14,
+ BFD_RELOC_HPPA_RS17,
+ BFD_RELOC_HPPA_LD21,
+ BFD_RELOC_HPPA_RD11,
+ BFD_RELOC_HPPA_RD14,
+ BFD_RELOC_HPPA_RD17,
+ BFD_RELOC_HPPA_LR21,
+ BFD_RELOC_HPPA_RR14,
+ BFD_RELOC_HPPA_RR17,
+
+ BFD_RELOC_HPPA_GOTOFF_11,
+ BFD_RELOC_HPPA_GOTOFF_14,
+ BFD_RELOC_HPPA_GOTOFF_L21,
+ BFD_RELOC_HPPA_GOTOFF_R11,
+ BFD_RELOC_HPPA_GOTOFF_R14,
+ BFD_RELOC_HPPA_GOTOFF_LS21,
+ BFD_RELOC_HPPA_GOTOFF_RS11,
+ BFD_RELOC_HPPA_GOTOFF_RS14,
+ BFD_RELOC_HPPA_GOTOFF_LD21,
+ BFD_RELOC_HPPA_GOTOFF_RD11,
+ BFD_RELOC_HPPA_GOTOFF_RD14,
+ BFD_RELOC_HPPA_GOTOFF_LR21,
+ BFD_RELOC_HPPA_GOTOFF_RR14,
+
+ BFD_RELOC_HPPA_DLT_32,
+ BFD_RELOC_HPPA_DLT_11,
+ BFD_RELOC_HPPA_DLT_14,
+ BFD_RELOC_HPPA_DLT_L21,
+ BFD_RELOC_HPPA_DLT_R11,
+ BFD_RELOC_HPPA_DLT_R14,
+
+ BFD_RELOC_HPPA_ABS_CALL_11,
+ BFD_RELOC_HPPA_ABS_CALL_14,
+ BFD_RELOC_HPPA_ABS_CALL_17,
+ BFD_RELOC_HPPA_ABS_CALL_L21,
+ BFD_RELOC_HPPA_ABS_CALL_R11,
+ BFD_RELOC_HPPA_ABS_CALL_R14,
+ BFD_RELOC_HPPA_ABS_CALL_R17,
+ BFD_RELOC_HPPA_ABS_CALL_LS21,
+ BFD_RELOC_HPPA_ABS_CALL_RS11,
+ BFD_RELOC_HPPA_ABS_CALL_RS14,
+ BFD_RELOC_HPPA_ABS_CALL_RS17,
+ BFD_RELOC_HPPA_ABS_CALL_LD21,
+ BFD_RELOC_HPPA_ABS_CALL_RD11,
+ BFD_RELOC_HPPA_ABS_CALL_RD14,
+ BFD_RELOC_HPPA_ABS_CALL_RD17,
+ BFD_RELOC_HPPA_ABS_CALL_LR21,
+ BFD_RELOC_HPPA_ABS_CALL_RR14,
+ BFD_RELOC_HPPA_ABS_CALL_RR17,
+
+ BFD_RELOC_HPPA_PCREL_CALL_11,
+ BFD_RELOC_HPPA_PCREL_CALL_12,
+ BFD_RELOC_HPPA_PCREL_CALL_14,
+ BFD_RELOC_HPPA_PCREL_CALL_17,
+ BFD_RELOC_HPPA_PCREL_CALL_L21,
+ BFD_RELOC_HPPA_PCREL_CALL_R11,
+ BFD_RELOC_HPPA_PCREL_CALL_R14,
+ BFD_RELOC_HPPA_PCREL_CALL_R17,
+ BFD_RELOC_HPPA_PCREL_CALL_LS21,
+ BFD_RELOC_HPPA_PCREL_CALL_RS11,
+ BFD_RELOC_HPPA_PCREL_CALL_RS14,
+ BFD_RELOC_HPPA_PCREL_CALL_RS17,
+ BFD_RELOC_HPPA_PCREL_CALL_LD21,
+ BFD_RELOC_HPPA_PCREL_CALL_RD11,
+ BFD_RELOC_HPPA_PCREL_CALL_RD14,
+ BFD_RELOC_HPPA_PCREL_CALL_RD17,
+ BFD_RELOC_HPPA_PCREL_CALL_LR21,
+ BFD_RELOC_HPPA_PCREL_CALL_RR14,
+ BFD_RELOC_HPPA_PCREL_CALL_RR17,
+
+ BFD_RELOC_HPPA_PLABEL_32,
+ BFD_RELOC_HPPA_PLABEL_11,
+ BFD_RELOC_HPPA_PLABEL_14,
+ BFD_RELOC_HPPA_PLABEL_L21,
+ BFD_RELOC_HPPA_PLABEL_R11,
+ BFD_RELOC_HPPA_PLABEL_R14,
+
+ BFD_RELOC_HPPA_UNWIND_ENTRY,
+ BFD_RELOC_HPPA_UNWIND_ENTRIES,
+
+ /* 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,
+
+ /* 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
+
+ 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 get_symtab_upper_bound(abfd) \
+ BFD_SEND (abfd, _get_symtab_upper_bound, (abfd))
+#define bfd_canonicalize_symtab(abfd, location) \
+ BFD_SEND (abfd, _bfd_canonicalize_symtab,\
+ (abfd, location))
+boolean
+bfd_set_symtab PARAMS ((bfd *, asymbol **, unsigned int ));
+
+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. */
+ 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 being cached */
+
+ boolean cacheable;
+
+ /* Marks whether there was a default target specified when the
+ BFD was opened. This is used to select what matching algorithm
+ to use to chose 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:*/
+
+ 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.*/
+
+ 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
+ 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*/
+ 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;
+ struct _bfd *next;
+ struct _bfd *archive_head;
+ boolean has_armap;
+
+ /* 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 hppa_data_struct *hppa_data;
+ struct hpux_core_struct *hpux_core_data;
+ struct sgi_core_struct *sgi_core_data;
+ struct lynx_core_struct *lynx_core_data;
+ struct osf_core_struct *osf_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;
+
+ /* Is this really needed in addition to usrdata? */
+ asymbol **ld_symbols;
+};
+
+unsigned int
+bfd_get_reloc_upper_bound PARAMS ((bfd *abfd, asection *sect));
+
+unsigned int
+bfd_canonicalize_reloc
+ PARAMS ((bfd *abfd,
+ asection *sec,
+ arelent **loc,
+ asymbol **syms));
+
+boolean
+bfd_set_file_flags PARAMS ((bfd *abfd, flagword flags));
+
+void
+bfd_set_reloc
+ PARAMS ((bfd *abfd, asection *sec, arelent **rel, unsigned int count)
+
+ );
+
+boolean
+bfd_set_start_address PARAMS ((bfd *, bfd_vma));
+
+long
+bfd_get_mtime PARAMS ((bfd *));
+
+long
+bfd_get_size PARAMS ((bfd *));
+
+int
+bfd_get_gp_size PARAMS ((bfd *));
+
+void
+bfd_set_gp_size PARAMS ((bfd *, int));
+
+bfd_vma
+bfd_scan_vma PARAMS ((CONST char *string, CONST char **end, int base));
+
+#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, seclet, data, relocateable) \
+ BFD_SEND (abfd, _bfd_get_relocated_section_contents, (abfd, seclet, data, relocateable))
+
+#define bfd_relax_section(abfd, section, symbols) \
+ BFD_SEND (abfd, _bfd_relax_section, (abfd, section, symbols))
+
+#define bfd_seclet_link(abfd, data, relocateable) \
+ BFD_SEND (abfd, _bfd_seclet_link, (abfd, data, relocateable))
+symindex
+bfd_get_next_mapent PARAMS ((bfd *, 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 *));
+
+int
+bfd_core_file_failing_signal PARAMS ((bfd *));
+
+boolean
+core_file_matches_executable_p
+ PARAMS ((bfd *core_bfd, bfd *exec_bfd));
+
+#define BFD_SEND(bfd, message, arglist) \
+ ((*((bfd)->xvec->message)) arglist)
+#define BFD_SEND_FMT(bfd, message, arglist) \
+ (((bfd)->xvec->message[(int)((bfd)->format)]) arglist)
+typedef struct bfd_target
+{
+ char *name;
+ enum target_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_hppa_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 ((bfd_byte *));
+ bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((bfd_byte *));
+ void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_getx32) PARAMS ((bfd_byte *));
+ bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((bfd_byte *));
+ void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_getx16) PARAMS ((bfd_byte *));
+ bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((bfd_byte *));
+ void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_h_getx64) PARAMS ((bfd_byte *));
+ bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((bfd_byte *));
+ void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_h_getx32) PARAMS ((bfd_byte *));
+ bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((bfd_byte *));
+ void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *));
+ bfd_vma (*bfd_h_getx16) PARAMS ((bfd_byte *));
+ bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((bfd_byte *));
+ void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *));
+ 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 *));
+ char * (*_core_file_failing_command) PARAMS ((bfd *));
+ int (*_core_file_failing_signal) PARAMS ((bfd *));
+ boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *));
+ 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));
+ boolean (*_close_and_cleanup) PARAMS ((bfd *));
+ boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+ file_ptr, bfd_size_type));
+ boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+ file_ptr, bfd_size_type));
+ boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr));
+ unsigned int (*_get_symtab_upper_bound) PARAMS ((bfd *));
+ unsigned int (*_bfd_canonicalize_symtab) PARAMS ((bfd *,
+ struct symbol_cache_entry **));
+ unsigned int (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr));
+ unsigned int (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **,
+ 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))
+ alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *));
+
+ boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture,
+ unsigned long));
+
+ bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev));
+
+ 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));
+
+ int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *));
+
+ int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean));
+
+ void (*_bfd_debug_info_start) PARAMS ((bfd *));
+ void (*_bfd_debug_info_end) PARAMS ((bfd *));
+ void (*_bfd_debug_info_accumulate) PARAMS ((bfd *, struct sec *));
+
+ bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *,
+ struct bfd_seclet *, bfd_byte *data,
+ boolean relocateable));
+
+ boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *,
+ struct symbol_cache_entry **));
+
+ boolean (*_bfd_seclet_link) PARAMS ((bfd *, PTR data,
+ boolean relocateable));
+ /* See documentation on reloc types. */
+ CONST struct reloc_howto_struct *
+ (*reloc_type_lookup) PARAMS ((bfd *abfd,
+ bfd_reloc_code_real_type code));
+
+ /* 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));
+ PTR backend_data;
+} bfd_target;
+bfd_target *
+bfd_find_target PARAMS ((CONST char *, bfd *));
+
+CONST char **
+bfd_target_list PARAMS ((void));
+
+boolean
+bfd_check_format PARAMS ((bfd *abfd, bfd_format format));
+
+boolean
+bfd_set_format PARAMS ((bfd *, bfd_format));
+
+CONST char *
+bfd_format_string PARAMS ((bfd_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..f8cfd19
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/cache.c
@@ -0,0 +1,311 @@
+/* BFD library -- caching of file descriptors.
+ Copyright 1990, 1991, 1992 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"
+
+/*
+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
+
+*/
+
+
+static boolean
+bfd_cache_delete PARAMS ((bfd *));
+
+/* Number of bfds on the chain. All such bfds have their file open;
+ if it closed, they get snipd()d from the chain. */
+
+static int open_files;
+
+static bfd *cache_sentinel; /* Chain of BFDs with active fds we've
+ opened */
+
+/*
+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
+ * Checks to see if the required BFD is the same as the last one
+ * looked up. If so then it can use the iostream 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))
+ *
+ *
+ */
+
+static void
+DEFUN_VOID(close_one)
+{
+ bfd *kill = cache_sentinel;
+ if (kill == 0) /* Nothing in the cache */
+ return ;
+
+ /* We can only close files that want to play this game. */
+ while (!kill->cacheable) {
+ kill = kill->lru_prev;
+ if (kill == cache_sentinel) /* Nobody wants to play */
+ return ;
+ }
+
+ kill->where = ftell((FILE *)(kill->iostream));
+ (void) bfd_cache_delete(kill);
+}
+
+/* Cuts the BFD abfd out of the chain in the cache */
+static void
+DEFUN(snip,(abfd),
+ bfd *abfd)
+{
+ abfd->lru_prev->lru_next = abfd->lru_next;
+ abfd->lru_next->lru_prev = abfd->lru_prev;
+ if (cache_sentinel == abfd) cache_sentinel = (bfd *)NULL;
+}
+
+static boolean
+DEFUN(bfd_cache_delete,(abfd),
+ bfd *abfd)
+{
+ boolean ret;
+
+ if (fclose ((FILE *)(abfd->iostream)) == 0)
+ ret = true;
+ else
+ {
+ ret = false;
+ bfd_error = system_call_error;
+ }
+ snip (abfd);
+ abfd->iostream = NULL;
+ open_files--;
+ bfd_last_cache = 0;
+ return ret;
+}
+
+static bfd *
+DEFUN(insert,(x,y),
+ bfd *x AND
+ bfd *y)
+{
+ if (y) {
+ x->lru_next = y;
+ x->lru_prev = y->lru_prev;
+ y->lru_prev->lru_next = x;
+ y->lru_prev = x;
+
+ }
+ else {
+ x->lru_prev = x;
+ x->lru_next = x;
+ }
+ return x;
+}
+
+
+/* Initialize a BFD by putting it on the cache LRU. */
+
+void
+DEFUN(bfd_cache_init,(abfd),
+ bfd *abfd)
+{
+ if (open_files >= BFD_CACHE_MAX_OPEN)
+ close_one ();
+ cache_sentinel = insert(abfd, cache_sentinel);
+ ++open_files;
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_cache_close
+
+DESCRIPTION
+ Remove the BFD from the cache. If the attached file is open,
+ then close it too.
+
+SYNOPSIS
+ boolean bfd_cache_close (bfd *);
+
+RETURNS
+ <<false>> is returned if closing the file fails, <<true>> is
+ returned if all is well.
+*/
+boolean
+DEFUN(bfd_cache_close,(abfd),
+ bfd *abfd)
+{
+ /* If this file is open then remove from the chain */
+ if (abfd->iostream)
+ {
+ return bfd_cache_delete(abfd);
+ }
+ else
+ {
+ return true;
+ }
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_open_file
+
+DESCRIPTION
+ Call the OS to open a file for this BFD. Returns the FILE *
+ (possibly null) that results from this operation. Sets up the
+ BFD so that future accesses know the file is open. If the FILE
+ * returned is null, then there is won't have been put in the
+ cache, so it won't have to be removed from it.
+
+SYNOPSIS
+ FILE* bfd_open_file(bfd *);
+*/
+
+FILE *
+DEFUN(bfd_open_file, (abfd),
+ bfd *abfd)
+{
+ abfd->cacheable = true; /* Allow it to be closed later. */
+
+ if(open_files >= BFD_CACHE_MAX_OPEN) {
+ close_one();
+ }
+
+ 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) {
+ 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) {
+ bfd_cache_init (abfd);
+ }
+
+ return (FILE *)(abfd->iostream);
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_cache_lookup_worker
+
+DESCRIPTION
+ Called when the macro <<bfd_cache_lookup>> fails to find a
+ quick answer. Finds a file descriptor for this BFD. If
+ necessary, it open it. If there are already more than
+ BFD_CACHE_MAX_OPEN files open, it trys to close one first, to
+ avoid running out of file descriptors.
+
+SYNOPSIS
+ FILE *bfd_cache_lookup_worker(bfd *);
+
+*/
+
+FILE *
+DEFUN(bfd_cache_lookup_worker,(abfd),
+ bfd *abfd)
+{
+ if (abfd->my_archive)
+ {
+ abfd = abfd->my_archive;
+ }
+ /* Is this file already open .. if so then quick exit */
+ if (abfd->iostream)
+ {
+ if (abfd != cache_sentinel) {
+ /* Place onto head of lru chain */
+ snip (abfd);
+ cache_sentinel = insert(abfd, cache_sentinel);
+ }
+ }
+ /* This is a BFD without a stream -
+ so it must have been closed or never opened.
+ find an empty cache entry and use it. */
+ else
+ {
+
+ if (open_files >= BFD_CACHE_MAX_OPEN)
+ {
+ close_one();
+ }
+
+ BFD_ASSERT(bfd_open_file (abfd) != (FILE *)NULL) ;
+ fseek((FILE *)(abfd->iostream), abfd->where, false);
+ }
+ bfd_last_cache = abfd;
+ return (FILE *)(abfd->iostream);
+}
diff --git a/gnu/usr.bin/gdb/bfd/coffgen.c b/gnu/usr.bin/gdb/bfd/coffgen.c
new file mode 100644
index 0000000..94cc225d
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/coffgen.c
@@ -0,0 +1,1519 @@
+/* Support for the generic parts of COFF, 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. */
+
+/* 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 "seclet.h"
+#include "libcoff.h"
+
+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
+DEFUN(make_a_section_from_file,(abfd, hdr, target_index),
+ bfd *abfd AND
+ struct internal_scnhdr *hdr AND
+ 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_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_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
+bfd_target *
+DEFUN(coff_real_object_p,(abfd, nscns, internal_f, internal_a),
+ bfd *abfd AND
+ unsigned nscns AND
+ struct internal_filehdr *internal_f AND
+ 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 (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;
+
+
+ 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 (bfd_target *)NULL;
+}
+
+/* Turn a COFF file into a BFD, but fail with wrong_format if it is
+ not a COFF file. This is also used by ECOFF. */
+
+bfd_target *
+DEFUN(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;
+
+ bfd_error = system_call_error;
+
+ /* 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)
+ 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_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 */
+ bfd_seek(abfd, (file_ptr) (internal_f.f_opthdr + filhsz), SEEK_SET);
+
+ 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. */
+
+struct sec *
+DEFUN(coff_section_from_bfd_index,(abfd, index),
+ bfd *abfd AND
+ int index)
+{
+ struct sec *answer = abfd->sections;
+
+ if (index == N_ABS)
+ {
+ return &bfd_abs_section;
+ }
+ if (index == N_UNDEF)
+ {
+ return &bfd_und_section;
+ }
+ if(index == N_DEBUG)
+ {
+ return &bfd_debug_section;
+
+ }
+
+ while (answer) {
+ if (answer->target_index == index)
+ return answer;
+ answer = answer->next;
+ }
+ BFD_ASSERT(0);
+ return &bfd_und_section; /* For gcc -W and lint. Never executed. */
+}
+
+/* Get the upper bound of a COFF symbol table. */
+
+unsigned int
+coff_get_symtab_upper_bound(abfd)
+bfd *abfd;
+{
+ if (!bfd_coff_slurp_symbol_table(abfd))
+ return 0;
+
+ return (bfd_get_symcount(abfd) + 1) * (sizeof(coff_symbol_type *));
+}
+
+
+/* Canonicalize a COFF symbol table. */
+
+unsigned int
+DEFUN(coff_get_symtab, (abfd, alocation),
+ bfd *abfd AND
+ 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 0;
+
+ 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
+DEFUN(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. */
+
+coff_symbol_type *
+DEFUN(coff_symbol_from,(ignore_abfd, symbol),
+ bfd *ignore_abfd AND
+ 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
+DEFUN(fixup_symbol_value,(coff_symbol_ptr, syment),
+coff_symbol_type *coff_symbol_ptr AND
+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 (coff_symbol_ptr->symbol.section == & bfd_und_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.
+
+*/
+void
+DEFUN(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));
+ bfd_ptr->outsymbols = newsyms;
+ for (i = 0; i < symbol_count; i++)
+ if (symbol_ptr_ptr[i]->section != &bfd_und_section)
+ *newsyms++ = symbol_ptr_ptr[i];
+ for (i = 0; i < symbol_count; i++)
+ if (symbol_ptr_ptr[i]->section == &bfd_und_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;
+}
+
+/*
+ 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
+DEFUN(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;
+
+ 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;
+
+ }
+
+ }
+ }
+ }
+}
+
+static int string_size;
+
+static void
+DEFUN(coff_fix_symbol_name,(abfd, symbol, native),
+ bfd *abfd AND
+ asymbol *symbol AND
+ 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 {
+ 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;
+ }
+ }
+}
+
+#define set_index(symbol, idx) ((symbol)->udata =(PTR) (idx))
+
+static unsigned int
+DEFUN(coff_write_symbol,(abfd, symbol, native, written),
+bfd *abfd AND
+asymbol *symbol AND
+combined_entry_type *native AND
+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 (symbol->section == &bfd_abs_section)
+ {
+ native->u.syment.n_scnum = N_ABS;
+ }
+ else if (symbol->section == &bfd_debug_section)
+ {
+ native->u.syment.n_scnum = N_DEBUG;
+ }
+ else if (symbol->section == &bfd_und_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);
+ bfd_coff_swap_sym_out(abfd, &native->u.syment, buf);
+ bfd_write(buf, 1, symesz, abfd);
+ 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);
+ for (j = 0; j < native->u.syment.n_numaux; j++)
+ {
+ bfd_coff_swap_aux_out(abfd,
+ &((native + j + 1)->u.auxent),
+ type,
+ class,
+ buf);
+ bfd_write(buf, 1, auxesz, abfd);
+ }
+ bfd_release (abfd, buf);
+ }
+ /*
+ Reuse somewhere in the symbol to keep the index
+ */
+ set_index(symbol, written);
+ return written + 1 + numaux;
+}
+
+
+static unsigned int
+DEFUN(coff_write_alien_symbol,(abfd, symbol, written),
+ bfd *abfd AND
+ asymbol *symbol AND
+ unsigned int written)
+{
+ /*
+ This symbol has been created by the loader, or come from a non
+ coff format. It has no native element to inherit, make our
+ own
+ */
+ combined_entry_type *native;
+ combined_entry_type dummy;
+ native = &dummy;
+ native->u.syment.n_type = T_NULL;
+ native->u.syment.n_flags = 0;
+ if (symbol->section == &bfd_und_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 name so it doesn't take up any space
+ */
+ 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 hdr into the symbol */
+ {
+ 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);
+}
+
+static unsigned int
+DEFUN(coff_write_native_symbol,(abfd, symbol, written),
+bfd *abfd AND
+coff_symbol_type *symbol AND
+unsigned int written)
+{
+ /*
+ Does this symbol have an ascociated line number - if so then
+ make it remember this symbol index. Also tag the auxent of
+ this symbol to point to the right place in the lineno table
+ */
+ combined_entry_type *native = symbol->native;
+
+ alent *lineno = symbol->lineno;
+
+ 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;
+ }
+ /*
+ And count and relocate all other linenumbers
+ */
+
+ count++;
+ while (lineno[count].line_number) {
+#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);
+}
+
+void
+DEFUN(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;
+
+
+ /* Seek to the right place */
+ bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET);
+
+ /* 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)
+ {
+ written = coff_write_alien_symbol(abfd, symbol, written);
+ }
+ else
+ {
+ written = coff_write_native_symbol(abfd, c_symbol, written);
+ }
+
+ }
+
+ 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);
+ bfd_write((PTR) buffer, 1, sizeof(buffer), abfd);
+ for (p = abfd->outsymbols, i = 0;
+ i < limit;
+ i++, p++)
+ {
+ asymbol *q = *p;
+ size_t name_length = strlen(q->name);
+ int maxlen;
+ coff_symbol_type* c_symbol = coff_symbol_from(abfd, q);
+ maxlen = ((c_symbol != NULL && c_symbol->native != NULL) &&
+ (c_symbol->native->u.syment.n_sclass == C_FILE)) ?
+ FILNMLEN : SYMNMLEN;
+
+ if (name_length > maxlen) {
+ bfd_write((PTR) (q->name), 1, name_length + 1, abfd);
+ }
+ }
+ }
+ 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);
+ bfd_write((PTR) buffer, 1, sizeof (buffer), abfd);
+ }
+}
+
+void
+DEFUN(coff_write_linenumbers,(abfd),
+ bfd *abfd)
+{
+ asection *s;
+ bfd_size_type linesz;
+ PTR buff;
+
+ linesz = bfd_coff_linesz (abfd);
+ buff = bfd_alloc (abfd, linesz);
+ for (s = abfd->sections; s != (asection *) NULL; s = s->next) {
+ if (s->lineno_count) {
+ asymbol **q = abfd->outsymbols;
+ bfd_seek(abfd, s->line_filepos, SEEK_SET);
+ /* 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);
+ bfd_write(buff, 1, linesz, abfd);
+ 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);
+ bfd_write(buff, 1, linesz, abfd);
+ l++;
+ }
+ }
+ }
+ q++;
+ }
+ }
+ }
+ bfd_release (abfd, buff);
+}
+
+alent *
+DEFUN(coff_get_lineno,(ignore_abfd, symbol),
+ bfd *ignore_abfd AND
+ 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));
+ 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
+DEFUN(coff_pointerize_aux,(abfd, table_base, type, class, auxent),
+bfd *abfd AND
+combined_entry_type *table_base AND
+int type AND
+int class AND
+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 *
+DEFUN(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)) {
+ bfd_error = system_call_error;
+ return (NULL);
+ } /* on error */
+
+ 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_error = no_memory;
+ return (NULL);
+ } /* on mallocation error */
+ if (bfd_read(string_table, string_table_size, 1, abfd) != string_table_size) {
+ bfd_error = system_call_error;
+ 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 *
+DEFUN(build_debug_section,(abfd),
+ bfd *abfd)
+{
+ char *debug_section;
+ long position;
+
+ asection *sect = bfd_get_section_by_name (abfd, ".debug");
+
+ if (!sect) {
+ 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_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);
+ bfd_seek (abfd, sect->filepos, SEEK_SET);
+ if (bfd_read (debug_section,
+ bfd_get_section_size_before_reloc (sect), 1, abfd)
+ != bfd_get_section_size_before_reloc(sect)) {
+ bfd_error = system_call_error;
+ return NULL;
+ }
+ bfd_seek (abfd, position, SEEK_SET);
+ 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 *
+DEFUN(copy_name,(abfd, name, maxlen),
+ bfd *abfd AND
+ char *name AND
+ 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_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 *
+DEFUN(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_error = no_symbols;
+ return (NULL);
+ }
+
+ internal = (combined_entry_type *)bfd_alloc(abfd, size);
+ 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 (bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET) == -1
+ || bfd_read(raw, raw_size, 1, abfd) != raw_size) {
+ bfd_error = system_call_error;
+ 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_tag = 0;
+ internal_ptr->fix_end = 0;
+ symbol_ptr = internal_ptr;
+
+ for (i = 0;
+ i < symbol_ptr->u.syment.n_numaux;
+ i++)
+ {
+ internal_ptr++;
+ raw_src += symesz;
+
+ internal_ptr->fix_tag = 0;
+ internal_ptr->fix_end = 0;
+ bfd_coff_swap_aux_in(abfd, (PTR) raw_src,
+ symbol_ptr->u.syment.n_type,
+ symbol_ptr->u.syment.n_sclass,
+ &(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_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 (!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() */
+
+unsigned int
+DEFUN (coff_get_reloc_upper_bound, (abfd, asect),
+ bfd *abfd AND
+ sec_ptr asect)
+{
+ if (bfd_get_format(abfd) != bfd_object) {
+ bfd_error = invalid_operation;
+ return 0;
+ }
+ return (asect->reloc_count + 1) * sizeof(arelent *);
+}
+
+asymbol *
+DEFUN (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_error = no_memory;
+ return (NULL);
+ } /* on error */
+ 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_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);
+ new->symbol.section = &bfd_debug_section;
+ new->lineno = (alent *) NULL;
+ new->done_lineno = false;
+ new->symbol.the_bfd = abfd;
+ return &new->symbol;
+}
+
+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%08x %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,
+ 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 %d",
+ 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%x",
+ l->line_number,
+ 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. */
+
+boolean
+DEFUN(coff_find_nearest_line,(abfd,
+ section,
+ ignore_symbols,
+ offset,
+ filename_ptr,
+ functionname_ptr,
+ line_ptr),
+ bfd *abfd AND
+ asection *section AND
+ asymbol **ignore_symbols AND
+ bfd_vma offset AND
+ CONST char **filename_ptr AND
+ CONST char **functionname_ptr AND
+ 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
+DEFUN(coff_sizeof_headers,(abfd, reloc),
+ bfd *abfd AND
+ 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/core.c b/gnu/usr.bin/gdb/bfd/core.c
new file mode 100644
index 0000000..c428775
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/core.c
@@ -0,0 +1,106 @@
+/* Core file generic interface routines for BFD.
+ Copyright (C) 1990-1991 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
+ Buff output this facinating topic
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+
+/*
+FUNCTION
+ bfd_core_file_failing_command
+
+SYNOPSIS
+ CONST char *bfd_core_file_failing_command(bfd *);
+
+DESCRIPTION
+ Returns a read-only string explaining what program was running
+ when it failed and produced the core file being read
+
+*/
+
+CONST char *
+DEFUN(bfd_core_file_failing_command,(abfd),
+ bfd *abfd)
+{
+ if (abfd->format != bfd_core) {
+ 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 *);
+
+DESCRIPTION
+ Returns the signal number which caused the core dump which
+ generated the file the BFD is attached to.
+*/
+
+int
+bfd_core_file_failing_signal (abfd)
+ bfd *abfd;
+{
+ if (abfd->format != bfd_core) {
+ 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
+ Returns <<true>> if the core file attached to @var{core_bfd}
+ was generated by a run of the executable file attached to
+ @var{exec_bfd}, or else <<false>>.
+*/
+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_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..b4afdb2
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/cpu-i386.c
@@ -0,0 +1,43 @@
+/* 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 DEFUN_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..adc6919
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/ctor.c
@@ -0,0 +1,148 @@
+/* BFD library support routines for constructors
+ Copyright (C) 1990-1991 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 `constructors' and `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 data 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 <<main>>.
+ This magic function, (often called <<__main>>) runs around
+ calling the constructors for all the things needing it.
+
+ With COFF the compile 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 (ie the linker) to deal with
+ constructor information independently of their external
+ implimentation by providing a set of entry points for the
+ indiviual object back ends to call which maintains 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.
+
+ This module takes this information and then 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 do with
+ what it wants.
+
+*/
+
+#include <bfd.h>
+#include <sysdep.h>
+#include <libbfd.h>
+
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_constructor_entry
+
+SYNOPSIS
+ void bfd_constructor_entry(bfd *abfd,
+ asymbol **symbol_ptr_ptr,
+ CONST char*type);
+
+
+DESCRIPTION
+ This function is called with an a symbol describing the
+ function to be called, an string which descibes the xtor type,
+ e.g., something like "CTOR" or "DTOR" would be fine. And the bfd
+ which owns the function. Its duty is to 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.
+
+*/
+
+
+void DEFUN(bfd_constructor_entry,(abfd, symbol_ptr_ptr, type),
+ bfd *abfd AND
+ asymbol **symbol_ptr_ptr AND
+ 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));
+
+/* 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++;
+ }
+
+}
diff --git a/gnu/usr.bin/gdb/bfd/ecoff.c b/gnu/usr.bin/gdb/bfd/ecoff.c
new file mode 100644
index 0000000..e3b7c93
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/ecoff.c
@@ -0,0 +1,3994 @@
+/* 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 "libbfd.h"
+#include "seclet.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 void 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, char *string,
+ RNDXR *rndx, long isym,
+ CONST char *which));
+static char *ecoff_type_to_string PARAMS ((bfd *abfd, union aux_ext *aux_ptr,
+ unsigned int indx, int bigendian));
+static boolean ecoff_slurp_reloc_table PARAMS ((bfd *abfd, asection *section,
+ asymbol **symbols));
+static void ecoff_clear_output_flags PARAMS ((bfd *abfd));
+static boolean ecoff_rel PARAMS ((bfd *output_bfd, bfd_seclet_type *seclet,
+ asection *output_section, PTR data,
+ boolean relocateable));
+static boolean ecoff_dump_seclet PARAMS ((bfd *abfd, bfd_seclet_type *seclet,
+ asection *section, PTR data,
+ boolean relocateable));
+static long ecoff_add_string PARAMS ((bfd *output_bfd, FDR *fdr,
+ CONST char *string, boolean external));
+static boolean ecoff_get_debug PARAMS ((bfd *output_bfd,
+ bfd_seclet_type *seclet,
+ asection *section,
+ boolean relocateable));
+static void ecoff_compute_section_file_positions PARAMS ((bfd *abfd));
+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
+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_error = no_memory;
+ return false;
+ }
+
+ /* Always create a .scommon section for every BFD. This is a hack so
+ that the linker has something to attach scSCommon symbols to. */
+ if (bfd_make_section (abfd, SCOMMON) == NULL)
+ return false;
+
+ return true;
+}
+
+/* This is a hook called by coff_real_object_p to create any backend
+ specific information. */
+
+PTR
+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;
+ asection *regsec;
+
+ if (ecoff_mkobject (abfd) == false)
+ return NULL;
+
+ ecoff = ecoff_data (abfd);
+ ecoff->gp_size = 8;
+ ecoff->sym_filepos = internal_f->f_symptr;
+
+ /* Create the .reginfo section to give programs outside BFD a way to
+ see the information stored in the a.out header. See the comment
+ in coff/ecoff.h. */
+ regsec = bfd_make_section (abfd, REGINFO);
+ if (regsec == NULL)
+ return NULL;
+
+ 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. */
+
+asection *
+ecoff_make_section_hook (abfd, name)
+ bfd *abfd;
+ char *name;
+{
+ return (asection *) NULL;
+}
+
+/* Initialize a new section. */
+
+boolean
+ecoff_new_section_hook (abfd, section)
+ bfd *abfd;
+ asection *section;
+{
+ 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, REGINFO) == 0)
+ {
+ section->flags |= SEC_HAS_CONTENTS | SEC_NEVER_LOAD;
+ section->_raw_size = sizeof (struct ecoff_reginfo);
+ }
+
+ /* 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
+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 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. */
+
+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, _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 (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. */
+
+flagword
+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_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))
+ {
+ if (sec_flags & SEC_NEVER_LOAD)
+ sec_flags |= SEC_DATA | SEC_SHARED_LIBRARY;
+ else
+ sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
+ if (styp_flags & STYP_RDATA)
+ sec_flags |= SEC_READONLY;
+ }
+ else if ((styp_flags & STYP_BSS)
+ || (styp_flags & STYP_SBSS))
+ {
+ sec_flags |= SEC_ALLOC;
+ }
+ else if (styp_flags & STYP_INFO)
+ {
+ sec_flags |= SEC_NEVER_LOAD;
+ }
+ else if ((styp_flags & STYP_LIT8)
+ || (styp_flags & STYP_LIT4))
+ {
+ sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
+ }
+ 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
+ecoff_swap_tir_in (bigend, ext_copy, intern)
+ int bigend;
+ 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
+ecoff_swap_tir_out (bigend, intern_copy, ext)
+ int bigend;
+ 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
+ecoff_swap_rndx_in (bigend, ext_copy, intern)
+ int bigend;
+ 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)
+ | (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
+ecoff_swap_rndx_out (bigend, intern_copy, ext)
+ int bigend;
+ 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 and swap the important symbolic information for an ECOFF
+ object file. This is called by gdb. */
+
+boolean
+ecoff_slurp_symbolic_info (abfd)
+ bfd *abfd;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ bfd_size_type external_hdr_size;
+ 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;
+
+ /* 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;
+ }
+
+ /* 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->external_hdr_size;
+ if (bfd_get_symcount (abfd) != external_hdr_size)
+ {
+ bfd_error = bad_value;
+ return false;
+ }
+
+ /* Read the symbolic information header. */
+ raw = (PTR) alloca (external_hdr_size);
+ if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) == -1
+ || (bfd_read (raw, external_hdr_size, 1, abfd)
+ != external_hdr_size))
+ {
+ bfd_error = system_call_error;
+ return false;
+ }
+ internal_symhdr = &ecoff_data (abfd)->symbolic_header;
+ (*backend->swap_hdr_in) (abfd, raw, internal_symhdr);
+
+ if (internal_symhdr->magic != backend->sym_magic)
+ {
+ bfd_error = bad_value;
+ return false;
+ }
+
+ /* Now we can get the correct number of symbols. */
+ bfd_get_symcount (abfd) = (internal_symhdr->isymMax
+ + internal_symhdr->iextMax);
+
+ /* Read all the symbolic information at once. */
+ raw_base = ecoff_data (abfd)->sym_filepos + 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->external_dnr_size);
+ UPDATE_RAW_END (cbPdOffset, ipdMax, backend->external_pdr_size);
+ UPDATE_RAW_END (cbSymOffset, isymMax, backend->external_sym_size);
+ UPDATE_RAW_END (cbOptOffset, ioptMax, backend->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->external_fdr_size);
+ UPDATE_RAW_END (cbRfdOffset, crfd, backend->external_rfd_size);
+ UPDATE_RAW_END (cbExtOffset, iextMax, backend->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_error = no_memory;
+ return false;
+ }
+ if (bfd_read (raw, raw_size, 1, abfd) != raw_size)
+ {
+ bfd_error = system_call_error;
+ bfd_release (abfd, raw);
+ return false;
+ }
+
+ ecoff_data (abfd)->raw_size = raw_size;
+ 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) \
+ ecoff_data (abfd)->off2 = (type) NULL; \
+ else \
+ ecoff_data (abfd)->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. */
+ ecoff_data (abfd)->fdr =
+ (struct fdr *) bfd_alloc (abfd,
+ (internal_symhdr->ifdMax *
+ sizeof (struct fdr)));
+ if (ecoff_data (abfd)->fdr == NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+ external_fdr_size = backend->external_fdr_size;
+ fdr_ptr = ecoff_data (abfd)->fdr;
+ fraw_src = (char *) ecoff_data (abfd)->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->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 *
+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_error = no_memory;
+ return (asymbol *) NULL;
+ }
+ memset (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 void
+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;
+ *indirect_ptr_ptr = NULL;
+ return;
+ }
+
+ 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;
+ /* Pass this symbol on to the next call to this function. */
+ *indirect_ptr_ptr = asym;
+ return;
+ }
+
+ /* 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;
+ }
+ break;
+ default:
+ asym->flags = BSF_DEBUGGING;
+ return;
+ }
+
+ 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;
+ break;
+ case scUndefined:
+ asym->section = &bfd_und_section;
+ 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;
+ 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;
+ 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);
+ 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));
+ 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;
+ }
+ }
+}
+
+/* Read an ECOFF symbol table. */
+
+boolean
+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->external_ext_size;
+ const bfd_size_type external_sym_size = backend->external_sym_size;
+ void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
+ = backend->swap_ext_in;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
+ = backend->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 (ecoff_slurp_symbolic_info (abfd) == false)
+ 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_error = no_memory;
+ return false;
+ }
+
+ internal_ptr = internal;
+ indirect_ptr = NULL;
+ eraw_src = (char *) ecoff_data (abfd)->external_ext;
+ eraw_end = (eraw_src
+ + (ecoff_data (abfd)->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)->ssext
+ + internal_esym.asym.iss);
+ ecoff_set_symbol_info (abfd, &internal_esym.asym,
+ &internal_ptr->symbol, 1, &indirect_ptr);
+ /* The alpha uses a negative ifd field for section symbols. */
+ if (internal_esym.ifd >= 0)
+ internal_ptr->fdr = ecoff_data (abfd)->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)->fdr;
+ fdr_end = fdr_ptr + ecoff_data (abfd)->symbolic_header.ifdMax;
+ for (; fdr_ptr < fdr_end; fdr_ptr++)
+ {
+ char *lraw_src;
+ char *lraw_end;
+
+ lraw_src = ((char *) ecoff_data (abfd)->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)->ss
+ + fdr_ptr->issBase
+ + internal_sym.iss);
+ ecoff_set_symbol_info (abfd, &internal_sym,
+ &internal_ptr->symbol, 0, &indirect_ptr);
+ 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. */
+
+unsigned int
+ecoff_get_symtab_upper_bound (abfd)
+ bfd *abfd;
+{
+ if (ecoff_slurp_symbolic_info (abfd) == false
+ || bfd_get_symcount (abfd) == 0)
+ return 0;
+
+ return (bfd_get_symcount (abfd) + 1) * (sizeof (ecoff_symbol_type *));
+}
+
+/* Get the canonicals symbols. */
+
+unsigned int
+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 (ecoff_slurp_symbol_table (abfd) == false
+ || 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, string, rndx, isym, which)
+ bfd *abfd;
+ char *string;
+ RNDXR *rndx;
+ long isym;
+ CONST char *which;
+{
+ int ifd = rndx->rfd;
+ int indx = rndx->index;
+ int sym_base, ss_base;
+ CONST char *name;
+
+ if (ifd == 0xfff)
+ ifd = isym;
+
+ sym_base = ecoff_data (abfd)->fdr[ifd].isymBase;
+ ss_base = ecoff_data (abfd)->fdr[ifd].issBase;
+
+ if (indx == indexNil)
+ name = "/* no name */";
+ else
+ {
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ SYMR sym;
+
+ indx += sym_base;
+ (*backend->swap_sym_in) (abfd,
+ ((char *) ecoff_data (abfd)->external_sym
+ + indx * backend->external_sym_size),
+ &sym);
+ name = ecoff_data (abfd)->ss + ss_base + sym.iss;
+ }
+
+ sprintf (string,
+ "%s %s { ifd = %d, index = %d }",
+ which, name, ifd,
+ indx + ecoff_data (abfd)->symbolic_header.iextMax);
+}
+
+/* Convert the type information to string format. */
+
+static char *
+ecoff_type_to_string (abfd, aux_ptr, indx, bigendian)
+ bfd *abfd;
+ union aux_ext *aux_ptr;
+ unsigned int indx;
+ 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;
+
+ 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)";
+ 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) */
+ ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+ ecoff_emit_aggregate (abfd, p1, &rndx,
+ 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 */
+ ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+ ecoff_emit_aggregate (abfd, p1, &rndx,
+ 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 */
+ ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+ ecoff_emit_aggregate (abfd, p1, &rndx,
+ 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. */
+
+void
+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
+ecoff_print_symbol (abfd, filep, symbol, how)
+ bfd *abfd;
+ PTR filep;
+ asymbol *symbol;
+ bfd_print_symbol_type how;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ 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;
+
+ (*backend->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;
+
+ (*backend->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)
+ {
+ (*backend->swap_sym_in) (abfd, ecoffsymbol (symbol)->native,
+ &ecoff_ext.asym);
+ type = 'l';
+ pos = ((((char *) ecoffsymbol (symbol)->native
+ - (char *) ecoff_data (abfd)->external_sym)
+ / backend->external_sym_size)
+ + ecoff_data (abfd)->symbolic_header.iextMax);
+ jmptbl = ' ';
+ cobol_main = ' ';
+ weakext = ' ';
+ }
+ else
+ {
+ (*backend->swap_ext_in) (abfd, ecoffsymbol (symbol)->native,
+ &ecoff_ext);
+ type = 'e';
+ pos = (((char *) ecoffsymbol (symbol)->native
+ - (char *) ecoff_data (abfd)->external_ext)
+ / backend->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)
+ {
+ unsigned int indx;
+ int bigendian;
+ bfd_size_type sym_base;
+ union aux_ext *aux_base;
+
+ 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 = ecoffsymbol (symbol)->fdr->isymBase;
+ if (ecoffsymbol (symbol)->local)
+ sym_base += ecoff_data (abfd)->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)->external_aux
+ + ecoffsymbol (symbol)->fdr->iauxBase);
+
+ /* The aux entries are stored in host byte order; the
+ order is indicated by a bit in the fdr. */
+ bigendian = ecoffsymbol (symbol)->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, aux_base, indx + 1,
+ bigendian));
+ else
+ fprintf (file, "\n Local symbol: %d",
+ (indx
+ + sym_base
+ + ecoff_data (abfd)->symbolic_header.iextMax));
+ break;
+
+ default:
+ if (! ECOFF_IS_STAB (&ecoff_ext.asym))
+ fprintf (file, "\n Type: %s",
+ ecoff_type_to_string (abfd, aux_base, indx,
+ bigendian));
+ 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 (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_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)
+ {
+ bfd_error = system_call_error;
+ 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)->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.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_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->finish_reloc) (abfd, &intern, rptr);
+ }
+
+ bfd_release (abfd, external_relocs);
+
+ section->relocation = internal_relocs;
+
+ return true;
+}
+
+/* Get a canonical list of relocs. */
+
+unsigned int
+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 0;
+
+ tblptr = section->relocation;
+ if (tblptr == (arelent *) NULL)
+ return 0;
+
+ 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. */
+
+boolean
+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_backend_data * const backend = ecoff_backend (abfd);
+ 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;
+ 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 (ecoff_slurp_symbolic_info (abfd) == false
+ || 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)->fdr;
+ fdr_end = fdr_start + ecoff_data (abfd)->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 = backend->external_pdr_size;
+ pdr_ptr = ((char *) ecoff_data (abfd)->external_pdr
+ + fdr_ptr->ipdFirst * external_pdr_size);
+ pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size;
+ (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+
+ /* The address of the first PDR is an offset which applies to the
+ addresses of all the PDR's. */
+ offset += pdr.adr;
+
+ for (pdr_ptr += external_pdr_size;
+ pdr_ptr < pdr_end;
+ pdr_ptr += external_pdr_size)
+ {
+ (*backend->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)->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;
+ (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+
+ offset -= pdr.adr;
+ lineno = pdr.lnLow;
+ line_ptr = (ecoff_data (abfd)->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;
+
+ (*backend->swap_ext_in) (abfd,
+ ((char *) ecoff_data (abfd)->external_ext
+ + pdr.isym * backend->external_ext_size),
+ &proc_ext);
+ *functionname_ptr = ecoff_data (abfd)->ssext + proc_ext.asym.iss;
+ }
+ }
+ else
+ {
+ SYMR proc_sym;
+
+ *filename_ptr = ecoff_data (abfd)->ss + fdr_ptr->issBase + fdr_ptr->rss;
+ (*backend->swap_sym_in) (abfd,
+ ((char *) ecoff_data (abfd)->external_sym
+ + ((fdr_ptr->isymBase + pdr.isym)
+ * backend->external_sym_size)),
+ &proc_sym);
+ *functionname_ptr = (ecoff_data (abfd)->ss
+ + fdr_ptr->issBase
+ + proc_sym.iss);
+ }
+ if (lineno == ilineNil)
+ lineno = 0;
+ *retline_ptr = lineno;
+ return true;
+}
+
+/* We can't use the generic linking routines for ECOFF, because we
+ have to handle all the debugging information. The generic link
+ routine just works out the section contents and attaches a list of
+ symbols.
+
+ We link by looping over all the seclets. We make two passes. On
+ the first we set the actual section contents and determine the size
+ of the debugging information. On the second we accumulate the
+ debugging information and write it out.
+
+ This currently always accumulates the debugging information, which
+ is incorrect, because it ignores the -s and -S options of the
+ linker. The linker needs to be modified to give us that
+ information in a more useful format (currently it just provides a
+ list of symbols which should appear in the output file). */
+
+/* Clear the output_has_begun flag for all the input BFD's. We use it
+ to avoid linking in the debugging information for a BFD more than
+ once. */
+
+static void
+ecoff_clear_output_flags (abfd)
+ bfd *abfd;
+{
+ register asection *o;
+ register bfd_seclet_type *p;
+
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ for (p = o->seclets_head;
+ p != (bfd_seclet_type *) NULL;
+ p = p->next)
+ if (p->type == bfd_indirect_seclet)
+ p->u.indirect.section->owner->output_has_begun = false;
+}
+
+/* Handle an indirect seclet on the first pass. Set the contents of
+ the output section, and accumulate the debugging information if
+ any. */
+
+static boolean
+ecoff_rel (output_bfd, seclet, output_section, data, relocateable)
+ bfd *output_bfd;
+ bfd_seclet_type *seclet;
+ asection *output_section;
+ PTR data;
+ boolean relocateable;
+{
+ bfd *input_bfd;
+ HDRR *output_symhdr;
+ HDRR *input_symhdr;
+
+ if ((output_section->flags & SEC_HAS_CONTENTS)
+ && !(output_section->flags & SEC_NEVER_LOAD)
+ && (output_section->flags & SEC_LOAD)
+ && seclet->size)
+ {
+ data = (PTR) bfd_get_relocated_section_contents (output_bfd,
+ seclet,
+ data,
+ relocateable);
+ if (bfd_set_section_contents (output_bfd,
+ output_section,
+ data,
+ seclet->offset,
+ seclet->size)
+ == false)
+ {
+ abort();
+ }
+ }
+
+ input_bfd = seclet->u.indirect.section->owner;
+
+ /* We want to figure out how much space will be required to
+ incorporate all the debugging information from input_bfd. We use
+ the output_has_begun field to avoid adding it in more than once.
+ The actual incorporation is done in the second pass, in
+ ecoff_get_debug. The code has to parallel that code in its
+ manipulations of output_symhdr. */
+
+ if (input_bfd->output_has_begun)
+ return true;
+ input_bfd->output_has_begun = true;
+
+ output_symhdr = &ecoff_data (output_bfd)->symbolic_header;
+
+ if (input_bfd->xvec->flavour != bfd_target_ecoff_flavour)
+ {
+ asymbol **symbols;
+ asymbol **sym_ptr;
+ asymbol **sym_end;
+
+ /* We just accumulate local symbols from a non-ECOFF BFD. The
+ external symbols are handled separately. */
+
+ symbols = (asymbol **) bfd_alloc (output_bfd,
+ get_symtab_upper_bound (input_bfd));
+ if (symbols == (asymbol **) NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+ sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols);
+
+ for (sym_ptr = symbols; sym_ptr < sym_end; sym_ptr++)
+ {
+ size_t len;
+
+ len = strlen ((*sym_ptr)->name);
+ if (((*sym_ptr)->flags & BSF_EXPORT) == 0)
+ {
+ ++output_symhdr->isymMax;
+ output_symhdr->issMax += len + 1;
+ }
+ }
+
+ bfd_release (output_bfd, (PTR) symbols);
+
+ ++output_symhdr->ifdMax;
+
+ return true;
+ }
+
+ /* We simply add in the information from another ECOFF BFD. First
+ we make sure we have the symbolic information. */
+ if (ecoff_slurp_symbol_table (input_bfd) == false)
+ return false;
+ if (bfd_get_symcount (input_bfd) == 0)
+ return true;
+
+ input_symhdr = &ecoff_data (input_bfd)->symbolic_header;
+
+ /* Figure out how much information we are going to be putting in.
+ The external symbols are handled separately. */
+ output_symhdr->ilineMax += input_symhdr->ilineMax;
+ output_symhdr->cbLine += input_symhdr->cbLine;
+ output_symhdr->idnMax += input_symhdr->idnMax;
+ output_symhdr->ipdMax += input_symhdr->ipdMax;
+ output_symhdr->isymMax += input_symhdr->isymMax;
+ output_symhdr->ioptMax += input_symhdr->ioptMax;
+ output_symhdr->iauxMax += input_symhdr->iauxMax;
+ output_symhdr->issMax += input_symhdr->issMax;
+ output_symhdr->ifdMax += input_symhdr->ifdMax;
+
+ /* The RFD's are special, since we create them if needed. */
+ if (input_symhdr->crfd > 0)
+ output_symhdr->crfd += input_symhdr->crfd;
+ else
+ output_symhdr->crfd += input_symhdr->ifdMax;
+
+ return true;
+}
+
+/* Handle an arbitrary seclet on the first pass. */
+
+static boolean
+ecoff_dump_seclet (abfd, seclet, section, data, relocateable)
+ bfd *abfd;
+ bfd_seclet_type *seclet;
+ asection *section;
+ PTR data;
+ boolean relocateable;
+{
+ switch (seclet->type)
+ {
+ case bfd_indirect_seclet:
+ /* The contents of this section come from another one somewhere
+ else. */
+ return ecoff_rel (abfd, seclet, section, data, relocateable);
+
+ case bfd_fill_seclet:
+ /* Fill in the section with fill.value. This is used to pad out
+ sections, but we must avoid padding the .bss section. */
+ if ((section->flags & SEC_HAS_CONTENTS) == 0)
+ {
+ if (seclet->u.fill.value != 0)
+ abort ();
+ }
+ else
+ {
+ char *d = (char *) bfd_alloc (abfd, seclet->size);
+ unsigned int i;
+ boolean ret;
+
+ for (i = 0; i < seclet->size; i+=2)
+ d[i] = seclet->u.fill.value >> 8;
+ for (i = 1; i < seclet->size; i+=2)
+ d[i] = seclet->u.fill.value;
+ ret = bfd_set_section_contents (abfd, section, d, seclet->offset,
+ seclet->size);
+ bfd_release (abfd, (PTR) d);
+ return ret;
+ }
+ break;
+
+ default:
+ abort();
+ }
+
+ return true;
+}
+
+/* Add a string to the debugging information we are accumulating for a
+ file. Return the offset from the fdr string base or from the
+ external string base. */
+
+static long
+ecoff_add_string (output_bfd, fdr, string, external)
+ bfd *output_bfd;
+ FDR *fdr;
+ CONST char *string;
+ boolean external;
+{
+ HDRR *symhdr;
+ size_t len;
+ long ret;
+
+ symhdr = &ecoff_data (output_bfd)->symbolic_header;
+ len = strlen (string);
+ if (external)
+ {
+ strcpy (ecoff_data (output_bfd)->ssext + symhdr->issExtMax, string);
+ ret = symhdr->issExtMax;
+ symhdr->issExtMax += len + 1;
+ }
+ else
+ {
+ strcpy (ecoff_data (output_bfd)->ss + symhdr->issMax, string);
+ ret = fdr->cbSs;
+ symhdr->issMax += len + 1;
+ fdr->cbSs += len + 1;
+ }
+ return ret;
+}
+
+/* Accumulate the debugging information from an input section. */
+
+static boolean
+ecoff_get_debug (output_bfd, seclet, section, relocateable)
+ bfd *output_bfd;
+ bfd_seclet_type *seclet;
+ asection *section;
+ boolean relocateable;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (output_bfd);
+ const bfd_size_type external_sym_size = backend->external_sym_size;
+ const bfd_size_type external_pdr_size = backend->external_pdr_size;
+ const bfd_size_type external_fdr_size = backend->external_fdr_size;
+ const bfd_size_type external_rfd_size = backend->external_rfd_size;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
+ = backend->swap_sym_in;
+ void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR))
+ = backend->swap_sym_out;
+ void (* const swap_pdr_in) PARAMS ((bfd *, PTR, PDR *))
+ = backend->swap_pdr_in;
+ void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR))
+ = backend->swap_fdr_out;
+ void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR))
+ = backend->swap_rfd_out;
+ bfd *input_bfd;
+ HDRR *output_symhdr;
+ HDRR *input_symhdr;
+ ecoff_data_type *output_ecoff;
+ ecoff_data_type *input_ecoff;
+ unsigned int count;
+ char *sym_out;
+ ecoff_symbol_type *esym_ptr;
+ ecoff_symbol_type *esym_end;
+ FDR *fdr_ptr;
+ FDR *fdr_end;
+ char *fdr_out;
+
+ input_bfd = seclet->u.indirect.section->owner;
+
+ /* Don't get the information more than once. */
+ if (input_bfd->output_has_begun)
+ return true;
+ input_bfd->output_has_begun = true;
+
+ output_ecoff = ecoff_data (output_bfd);
+ output_symhdr = &output_ecoff->symbolic_header;
+
+ if (input_bfd->xvec->flavour != bfd_target_ecoff_flavour)
+ {
+ FDR fdr;
+ asymbol **symbols;
+ asymbol **sym_ptr;
+ asymbol **sym_end;
+
+ /* This is not an ECOFF BFD. Just gather the symbols. */
+
+ memset (&fdr, 0, sizeof fdr);
+
+ fdr.adr = bfd_get_section_vma (output_bfd, section) + seclet->offset;
+ fdr.issBase = output_symhdr->issMax;
+ fdr.cbSs = 0;
+ fdr.rss = ecoff_add_string (output_bfd,
+ &fdr,
+ bfd_get_filename (input_bfd),
+ false);
+ fdr.isymBase = output_symhdr->isymMax;
+
+ /* Get the local symbols from the input BFD. */
+ symbols = (asymbol **) bfd_alloc (output_bfd,
+ get_symtab_upper_bound (input_bfd));
+ if (symbols == (asymbol **) NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+ sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols);
+
+ /* 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;
+
+ if (((*sym_ptr)->flags & BSF_EXPORT) != 0)
+ continue;
+ memset (&internal_sym, 0, sizeof internal_sym);
+ internal_sym.iss = ecoff_add_string (output_bfd,
+ &fdr,
+ (*sym_ptr)->name,
+ false);
+
+ if (bfd_is_com_section ((*sym_ptr)->section)
+ || (*sym_ptr)->section == &bfd_und_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;
+ (*swap_sym_out) (output_bfd, &internal_sym,
+ ((char *) output_ecoff->external_sym
+ + output_symhdr->isymMax * 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. */
+
+ (*swap_fdr_out) (output_bfd, &fdr,
+ ((char *) output_ecoff->external_fdr
+ + output_symhdr->ifdMax * external_fdr_size));
+ ++output_symhdr->ifdMax;
+ return true;
+ }
+
+ /* This is an ECOFF BFD. We want to grab the information from
+ input_bfd and attach it to output_bfd. */
+ count = bfd_get_symcount (input_bfd);
+ if (count == 0)
+ return true;
+ input_ecoff = ecoff_data (input_bfd);
+ input_symhdr = &input_ecoff->symbolic_header;
+
+ /* I think that it is more efficient to simply copy the debugging
+ information from the input BFD to the output BFD. Because ECOFF
+ uses relative pointers for most of the debugging information,
+ only a little of it has to be changed at all. */
+
+ /* Swap in the local symbols, adjust their values, and swap them out
+ again. The external symbols are handled separately. */
+ sym_out = ((char *) output_ecoff->external_sym
+ + output_symhdr->isymMax * external_sym_size);
+
+ esym_ptr = ecoff_data (input_bfd)->canonical_symbols;
+ esym_end = esym_ptr + count;
+ for (; esym_ptr < esym_end; esym_ptr++)
+ {
+ if (esym_ptr->local)
+ {
+ SYMR sym;
+
+ (*swap_sym_in) (input_bfd, esym_ptr->native, &sym);
+
+ /* If we're producing an executable, move common symbols
+ into bss. */
+ if (relocateable == false)
+ {
+ if (sym.sc == scCommon)
+ sym.sc = scBss;
+ else if (sym.sc == scSCommon)
+ sym.sc = scSBss;
+ }
+
+ if (! bfd_is_com_section (esym_ptr->symbol.section)
+ && (esym_ptr->symbol.flags & BSF_DEBUGGING) == 0
+ && esym_ptr->symbol.section != &bfd_und_section)
+ sym.value = (esym_ptr->symbol.value
+ + esym_ptr->symbol.section->output_offset
+ + esym_ptr->symbol.section->output_section->vma);
+ (*swap_sym_out) (output_bfd, &sym, sym_out);
+ sym_out += external_sym_size;
+ }
+ }
+
+ /* That should have accounted for all the local symbols in
+ input_bfd. */
+
+ /* Copy the information that does not need swapping. */
+ memcpy (output_ecoff->line + output_symhdr->cbLine,
+ input_ecoff->line,
+ input_symhdr->cbLine * sizeof (unsigned char));
+ memcpy (output_ecoff->external_aux + output_symhdr->iauxMax,
+ input_ecoff->external_aux,
+ input_symhdr->iauxMax * sizeof (union aux_ext));
+ memcpy (output_ecoff->ss + output_symhdr->issMax,
+ input_ecoff->ss,
+ input_symhdr->issMax * sizeof (char));
+
+ /* Some of the information may need to be swapped. */
+ if (output_bfd->xvec->header_byteorder_big_p
+ == input_bfd->xvec->header_byteorder_big_p)
+ {
+ /* The two BFD's have the same endianness, so memcpy will
+ suffice. */
+ if (input_symhdr->idnMax > 0)
+ memcpy (((char *) output_ecoff->external_dnr
+ + output_symhdr->idnMax * backend->external_dnr_size),
+ input_ecoff->external_dnr,
+ input_symhdr->idnMax * backend->external_dnr_size);
+ if (input_symhdr->ipdMax > 0)
+ memcpy (((char *) output_ecoff->external_pdr
+ + output_symhdr->ipdMax * external_pdr_size),
+ input_ecoff->external_pdr,
+ input_symhdr->ipdMax * external_pdr_size);
+ if (input_symhdr->ioptMax > 0)
+ memcpy (((char *) output_ecoff->external_opt
+ + output_symhdr->ioptMax * backend->external_opt_size),
+ input_ecoff->external_opt,
+ input_symhdr->ioptMax * backend->external_opt_size);
+ }
+ else
+ {
+ bfd_size_type sz;
+ char *in;
+ char *end;
+ char *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 slow in the normal case. */
+ sz = backend->external_dnr_size;
+ in = (char *) input_ecoff->external_dnr;
+ end = in + input_symhdr->idnMax * sz;
+ out = (char *) output_ecoff->external_dnr + output_symhdr->idnMax * sz;
+ for (; in < end; in += sz, out += sz)
+ {
+ DNR dnr;
+
+ (*backend->swap_dnr_in) (input_bfd, in, &dnr);
+ (*backend->swap_dnr_out) (output_bfd, &dnr, out);
+ }
+
+ sz = external_pdr_size;
+ in = (char *) input_ecoff->external_pdr;
+ end = in + input_symhdr->ipdMax * sz;
+ out = (char *) output_ecoff->external_pdr + output_symhdr->ipdMax * sz;
+ for (; in < end; in += sz, out += sz)
+ {
+ PDR pdr;
+
+ (*swap_pdr_in) (input_bfd, in, &pdr);
+ (*backend->swap_pdr_out) (output_bfd, &pdr, out);
+ }
+
+ sz = backend->external_opt_size;
+ in = (char *) input_ecoff->external_opt;
+ end = in + input_symhdr->ioptMax * sz;
+ out = (char *) output_ecoff->external_opt + output_symhdr->ioptMax * sz;
+ for (; in < end; in += sz, out += sz)
+ {
+ OPTR opt;
+
+ (*backend->swap_opt_in) (input_bfd, in, &opt);
+ (*backend->swap_opt_out) (output_bfd, &opt, out);
+ }
+ }
+
+ /* Set ifdbase so that the external symbols know how to adjust their
+ ifd values. */
+ input_ecoff->ifdbase = output_symhdr->ifdMax;
+
+ fdr_ptr = input_ecoff->fdr;
+ fdr_end = fdr_ptr + input_symhdr->ifdMax;
+ fdr_out = ((char *) output_ecoff->external_fdr
+ + output_symhdr->ifdMax * external_fdr_size);
+ for (; fdr_ptr < fdr_end; fdr_ptr++, fdr_out += external_fdr_size)
+ {
+ FDR fdr;
+ unsigned long pdr_off;
+
+ fdr = *fdr_ptr;
+
+ /* The memory address for this fdr is the address for the seclet
+ plus the offset to this fdr within input_bfd. For some
+ reason the offset of the first procedure pointer is also
+ added in. */
+ if (fdr.cpd == 0)
+ pdr_off = 0;
+ else
+ {
+ PDR pdr;
+
+ (*swap_pdr_in) (input_bfd,
+ ((char *) input_ecoff->external_pdr
+ + fdr.ipdFirst * external_pdr_size),
+ &pdr);
+ pdr_off = pdr.adr;
+ }
+ fdr.adr = (bfd_get_section_vma (output_bfd, section)
+ + seclet->offset
+ + (fdr_ptr->adr - input_ecoff->fdr->adr)
+ + pdr_off);
+
+ fdr.issBase += output_symhdr->issMax;
+ fdr.isymBase += output_symhdr->isymMax;
+ fdr.ilineBase += output_symhdr->ilineMax;
+ fdr.ioptBase += output_symhdr->ioptMax;
+ fdr.ipdFirst += output_symhdr->ipdMax;
+ fdr.iauxBase += output_symhdr->iauxMax;
+ fdr.rfdBase += output_symhdr->crfd;
+
+ /* If there are no RFD's, we are going to add some. We don't
+ want to adjust irfd for this, so that all the FDR's can share
+ the RFD's. */
+ if (input_symhdr->crfd == 0)
+ fdr.crfd = input_symhdr->ifdMax;
+
+ if (fdr.cbLine != 0)
+ fdr.cbLineOffset += output_symhdr->cbLine;
+
+ (*swap_fdr_out) (output_bfd, &fdr, fdr_out);
+ }
+
+ if (input_symhdr->crfd > 0)
+ {
+ void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *))
+ = backend->swap_rfd_in;
+ char *rfd_in;
+ char *rfd_end;
+ char *rfd_out;
+
+ /* Swap and adjust the RFD's. RFD's are only created by the
+ linker, so this will only be necessary if one of the input
+ files is the result of a partial link. Presumably all
+ necessary RFD's are present. */
+ rfd_in = (char *) input_ecoff->external_rfd;
+ rfd_end = rfd_in + input_symhdr->crfd * external_rfd_size;
+ rfd_out = ((char *) output_ecoff->external_rfd
+ + output_symhdr->crfd * external_rfd_size);
+ for (;
+ rfd_in < rfd_end;
+ rfd_in += external_rfd_size, rfd_out += external_rfd_size)
+ {
+ RFDT rfd;
+
+ (*swap_rfd_in) (input_bfd, rfd_in, &rfd);
+ rfd += output_symhdr->ifdMax;
+ (*swap_rfd_out) (output_bfd, &rfd, rfd_out);
+ }
+ output_symhdr->crfd += input_symhdr->crfd;
+ }
+ else
+ {
+ char *rfd_out;
+ char *rfd_end;
+ RFDT rfd;
+
+ /* Create RFD's. Some of the debugging information includes
+ relative file indices. These indices are taken as indices to
+ the RFD table if there is one, or to the global table if
+ there is not. If we did not create RFD's, we would have to
+ parse and adjust all the debugging information which contains
+ file indices. */
+ rfd = output_symhdr->ifdMax;
+ rfd_out = ((char *) output_ecoff->external_rfd
+ + output_symhdr->crfd * external_rfd_size);
+ rfd_end = rfd_out + input_symhdr->ifdMax * external_rfd_size;
+ for (; rfd_out < rfd_end; rfd_out += external_rfd_size, rfd++)
+ (*swap_rfd_out) (output_bfd, &rfd, rfd_out);
+ output_symhdr->crfd += input_symhdr->ifdMax;
+ }
+
+ /* Combine the register masks. Not all of these are used on all
+ targets, but that's OK because only the relevant ones will be
+ swapped in and out. */
+ {
+ int i;
+
+ output_ecoff->gprmask |= input_ecoff->gprmask;
+ output_ecoff->fprmask |= input_ecoff->fprmask;
+ for (i = 0; i < 4; i++)
+ output_ecoff->cprmask[i] |= input_ecoff->cprmask[i];
+ }
+
+ /* Update the counts. */
+ output_symhdr->ilineMax += input_symhdr->ilineMax;
+ output_symhdr->cbLine += input_symhdr->cbLine;
+ output_symhdr->idnMax += input_symhdr->idnMax;
+ output_symhdr->ipdMax += input_symhdr->ipdMax;
+ output_symhdr->isymMax += input_symhdr->isymMax;
+ output_symhdr->ioptMax += input_symhdr->ioptMax;
+ output_symhdr->iauxMax += input_symhdr->iauxMax;
+ output_symhdr->issMax += input_symhdr->issMax;
+ output_symhdr->ifdMax += input_symhdr->ifdMax;
+
+ return true;
+}
+
+/* This is the actual link routine. It makes two passes over all the
+ seclets. */
+
+boolean
+ecoff_bfd_seclet_link (abfd, data, relocateable)
+ bfd *abfd;
+ PTR data;
+ boolean relocateable;
+{
+ const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
+ HDRR *symhdr;
+ int ipass;
+ register asection *o;
+ register bfd_seclet_type *p;
+ asymbol **sym_ptr_ptr;
+ bfd_size_type debug_align;
+ bfd_size_type size;
+ char *raw;
+
+ /* We accumulate the debugging information counts in the symbolic
+ header. */
+ symhdr = &ecoff_data (abfd)->symbolic_header;
+ symhdr->magic = backend->sym_magic;
+ /* FIXME: What should the version stamp be? */
+ 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 need to copy over the debugging symbols from each input BFD.
+ When we do this copying, we have to adjust the text address in
+ the FDR structures, so we have to know the text address used for
+ the input BFD. Since we only want to copy the symbols once per
+ input BFD, but we are going to look at each input BFD multiple
+ times (once for each section it provides), we arrange to always
+ look at the text section first. That means that when we copy the
+ debugging information, we always know the text address. So we
+ actually do each pass in two sub passes; first the text sections,
+ then the non-text sections. We use the output_has_begun flag to
+ determine whether we have copied over the debugging information
+ yet. */
+
+ /* Do the first pass: set the output section contents and count the
+ debugging information. */
+ ecoff_clear_output_flags (abfd);
+ for (ipass = 0; ipass < 2; ipass++)
+ {
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ {
+ /* If this is a fake section, just forget it. The register
+ information is handled in another way. */
+ if (strcmp (o->name, SCOMMON) == 0
+ || strcmp (o->name, REGINFO) == 0)
+ continue;
+
+ /* For SEC_CODE sections, (flags & SEC_CODE) == 0 is false,
+ so they are done on pass 0. For other sections the
+ expression is true, so they are done on pass 1. */
+ if (((o->flags & SEC_CODE) == 0) != ipass)
+ continue;
+
+ for (p = o->seclets_head;
+ p != (bfd_seclet_type *) NULL;
+ p = p->next)
+ {
+ if (ecoff_dump_seclet (abfd, p, o, data, relocateable)
+ == false)
+ return false;
+ }
+ }
+ }
+
+ /* We handle the external symbols differently. We use the ones
+ attached to the output_bfd. The linker will have already
+ determined which symbols are to be attached. Here we just
+ determine how much space we will need for them. */
+ sym_ptr_ptr = bfd_get_outsymbols (abfd);
+ if (sym_ptr_ptr != NULL)
+ {
+ asymbol **sym_end;
+
+ sym_end = sym_ptr_ptr + bfd_get_symcount (abfd);
+ for (; sym_ptr_ptr < sym_end; sym_ptr_ptr++)
+ {
+ if (((*sym_ptr_ptr)->flags & BSF_DEBUGGING) == 0
+ && ((*sym_ptr_ptr)->flags & BSF_LOCAL) == 0)
+ {
+ ++symhdr->iextMax;
+ symhdr->issExtMax += strlen ((*sym_ptr_ptr)->name) + 1;
+ }
+ }
+ }
+
+ /* Adjust the counts so that structures are longword aligned. */
+ debug_align = backend->debug_align;
+ --debug_align;
+ symhdr->cbLine = (symhdr->cbLine + debug_align) &~ debug_align;
+ symhdr->issMax = (symhdr->issMax + debug_align) &~ debug_align;
+ symhdr->issExtMax = (symhdr->issExtMax + debug_align) &~ debug_align;
+
+ /* Now the counts in symhdr are the correct size for the debugging
+ information. We allocate the right amount of space, and reset
+ the counts so that the second pass can use them as indices. It
+ would be possible to output the debugging information directly to
+ the file in pass 2, rather than to build it in memory and then
+ write it out. Outputting to the file would require a lot of
+ seeks and small writes, though, and I think this approach is
+ faster. */
+ size = (symhdr->cbLine * sizeof (unsigned char)
+ + symhdr->idnMax * backend->external_dnr_size
+ + symhdr->ipdMax * backend->external_pdr_size
+ + symhdr->isymMax * backend->external_sym_size
+ + symhdr->ioptMax * backend->external_opt_size
+ + symhdr->iauxMax * sizeof (union aux_ext)
+ + symhdr->issMax * sizeof (char)
+ + symhdr->issExtMax * sizeof (char)
+ + symhdr->ifdMax * backend->external_fdr_size
+ + symhdr->crfd * backend->external_rfd_size
+ + symhdr->iextMax * backend->external_ext_size);
+ raw = (char *) bfd_alloc (abfd, size);
+ if (raw == (char *) NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+ ecoff_data (abfd)->raw_size = size;
+ ecoff_data (abfd)->raw_syments = (PTR) raw;
+
+ /* Initialize the raw pointers. */
+#define SET(field, count, type, size) \
+ ecoff_data (abfd)->field = (type) raw; \
+ raw += symhdr->count * size
+
+ SET (line, cbLine, unsigned char *, sizeof (unsigned char));
+ SET (external_dnr, idnMax, PTR, backend->external_dnr_size);
+ SET (external_pdr, ipdMax, PTR, backend->external_pdr_size);
+ SET (external_sym, isymMax, PTR, backend->external_sym_size);
+ SET (external_opt, ioptMax, PTR, backend->external_opt_size);
+ SET (external_aux, iauxMax, union aux_ext *, sizeof (union aux_ext));
+ SET (ss, issMax, char *, sizeof (char));
+ SET (ssext, issExtMax, char *, sizeof (char));
+ SET (external_fdr, ifdMax, PTR, backend->external_fdr_size);
+ SET (external_rfd, crfd, PTR, backend->external_rfd_size);
+ SET (external_ext, iextMax, PTR, backend->external_ext_size);
+#undef SET
+
+ /* Reset the counts so the second pass can use them to know how far
+ it has gotten. */
+ 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;
+
+ /* Do the second pass: accumulate the debugging information. */
+ ecoff_clear_output_flags (abfd);
+ for (ipass = 0; ipass < 2; ipass++)
+ {
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+ {
+ if (strcmp (o->name, SCOMMON) == 0
+ || strcmp (o->name, REGINFO) == 0)
+ continue;
+ if (((o->flags & SEC_CODE) == 0) != ipass)
+ continue;
+ for (p = o->seclets_head;
+ p != (bfd_seclet_type *) NULL;
+ p = p->next)
+ {
+ if (p->type == bfd_indirect_seclet)
+ {
+ if (ecoff_get_debug (abfd, p, o, relocateable) == false)
+ return false;
+ }
+ }
+ }
+ }
+
+ /* Put in the external symbols. */
+ sym_ptr_ptr = bfd_get_outsymbols (abfd);
+ if (sym_ptr_ptr != NULL)
+ {
+ const bfd_size_type external_ext_size = backend->external_ext_size;
+ void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
+ = backend->swap_ext_in;
+ void (* const swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR))
+ = backend->swap_ext_out;
+ char *ssext;
+ char *external_ext;
+
+ ssext = ecoff_data (abfd)->ssext;
+ external_ext = (char *) ecoff_data (abfd)->external_ext;
+ for (; *sym_ptr_ptr != NULL; sym_ptr_ptr++)
+ {
+ asymbol *sym_ptr;
+ EXTR esym;
+
+ sym_ptr = *sym_ptr_ptr;
+
+ if ((sym_ptr->flags & BSF_DEBUGGING) != 0
+ || (sym_ptr->flags & BSF_LOCAL) != 0)
+ continue;
+
+ /* The native pointer can be NULL for a symbol created by
+ the linker via ecoff_make_empty_symbol. */
+ if (bfd_asymbol_flavour (sym_ptr) != bfd_target_ecoff_flavour
+ || ecoffsymbol (sym_ptr)->native == NULL)
+ {
+ 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;
+ }
+ else
+ {
+ ecoff_symbol_type *ecoff_sym_ptr;
+
+ ecoff_sym_ptr = ecoffsymbol (sym_ptr);
+ if (ecoff_sym_ptr->local)
+ abort ();
+ (*swap_ext_in) (abfd, ecoff_sym_ptr->native, &esym);
+
+ /* 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;
+ }
+
+ /* Adjust the FDR index for the symbol by that used for
+ the input BFD. */
+ esym.ifd += ecoff_data (bfd_asymbol_bfd (sym_ptr))->ifdbase;
+ }
+
+ esym.asym.iss = symhdr->issExtMax;
+
+ if (bfd_is_com_section (sym_ptr->section)
+ || sym_ptr->section == &bfd_und_section)
+ esym.asym.value = sym_ptr->value;
+ else
+ esym.asym.value = (sym_ptr->value
+ + sym_ptr->section->output_offset
+ + sym_ptr->section->output_section->vma);
+
+ (*swap_ext_out) (abfd, &esym, external_ext);
+
+ ecoff_set_sym_index (sym_ptr, symhdr->iextMax);
+
+ external_ext += external_ext_size;
+ ++symhdr->iextMax;
+
+ strcpy (ssext + symhdr->issExtMax, sym_ptr->name);
+ symhdr->issExtMax += strlen (sym_ptr->name) + 1;
+ }
+ }
+
+ /* Adjust the counts so that structures are longword aligned. */
+ symhdr->cbLine = (symhdr->cbLine + debug_align) &~ debug_align;
+ symhdr->issMax = (symhdr->issMax + debug_align) &~ debug_align;
+ symhdr->issExtMax = (symhdr->issExtMax + debug_align) &~ debug_align;
+
+ 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
+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. We do not output the .scommon
+ section which we created in ecoff_mkobject, nor do we output any
+ .reginfo section. */
+
+int
+ecoff_sizeof_headers (abfd, reloc)
+ bfd *abfd;
+ boolean reloc;
+{
+ asection *current;
+ int c;
+
+ c = 0;
+ for (current = abfd->sections;
+ current != (asection *)NULL;
+ current = current->next)
+ if (strcmp (current->name, SCOMMON) != 0
+ && strcmp (current->name, REGINFO) != 0)
+ ++c;
+
+ return (bfd_coff_filhsz (abfd)
+ + bfd_coff_aoutsz (abfd)
+ + c * bfd_coff_scnhsz (abfd));
+}
+
+
+/* Get the contents of a section. This is where we handle reading the
+ .reginfo section, which implicitly holds the contents of an
+ ecoff_reginfo structure. */
+
+boolean
+ecoff_get_section_contents (abfd, section, location, offset, count)
+ bfd *abfd;
+ asection *section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ ecoff_data_type *tdata = ecoff_data (abfd);
+ struct ecoff_reginfo s;
+ int i;
+
+ if (strcmp (section->name, REGINFO) != 0)
+ return bfd_generic_get_section_contents (abfd, section, location,
+ offset, count);
+
+ s.gp_value = tdata->gp;
+ s.gprmask = tdata->gprmask;
+ for (i = 0; i < 4; i++)
+ s.cprmask[i] = tdata->cprmask[i];
+ s.fprmask = tdata->fprmask;
+
+ /* bfd_get_section_contents has already checked that the offset and
+ size is reasonable. We don't have to worry about swapping or any
+ such thing; the .reginfo section is defined such that the
+ contents are an ecoff_reginfo structure as seen on the host. */
+ memcpy (location, ((char *) &s) + offset, count);
+ return true;
+}
+
+/* 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;
+
+ if (bfd_get_start_address (abfd))
+ abfd->flags |= EXEC_P;
+
+ sofar = ecoff_sizeof_headers (abfd, false);
+
+ first_data = true;
+ for (current = abfd->sections;
+ current != (asection *) NULL;
+ current = current->next)
+ {
+ /* Only deal with sections which have contents */
+ if ((current->flags & (SEC_HAS_CONTENTS | SEC_LOAD)) == 0
+ || strcmp (current->name, SCOMMON) == 0
+ || strcmp (current->name, REGINFO) == 0)
+ continue;
+
+ /* 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? */
+ if ((abfd->flags & EXEC_P) != 0
+ && (abfd->flags & D_PAGED) != 0
+ && first_data != false
+ && (current->flags & SEC_CODE) == 0)
+ {
+ const bfd_vma round = ecoff_backend (abfd)->round;
+
+ sofar = (sofar + round - 1) &~ (round - 1);
+ first_data = false;
+ }
+
+ /* 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 << current->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 << current->alignment_power);
+ current->_raw_size += sofar - old_sofar;
+ }
+
+ ecoff_data (abfd)->reloc_filepos = sofar;
+}
+
+/* Set the contents of a section. This is where we handle setting the
+ contents of the .reginfo section, which implicitly holds a
+ ecoff_reginfo structure. */
+
+boolean
+ecoff_set_section_contents (abfd, section, location, offset, count)
+ bfd *abfd;
+ asection *section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
+{
+ if (abfd->output_has_begun == false)
+ ecoff_compute_section_file_positions (abfd);
+
+ if (strcmp (section->name, REGINFO) == 0)
+ {
+ ecoff_data_type *tdata = ecoff_data (abfd);
+ struct ecoff_reginfo s;
+ int i;
+
+ /* If the caller is only changing part of the structure, we must
+ retrieve the current information before the memcpy. */
+ if (offset != 0 || count != sizeof (struct ecoff_reginfo))
+ {
+ s.gp_value = tdata->gp;
+ s.gprmask = tdata->gprmask;
+ for (i = 0; i < 4; i++)
+ s.cprmask[i] = tdata->cprmask[i];
+ s.fprmask = tdata->fprmask;
+ }
+
+ /* bfd_set_section_contents has already checked that the offset
+ and size is reasonable. We don't have to worry about
+ swapping or any such thing; the .reginfo section is defined
+ such that the contents are an ecoff_reginfo structure as seen
+ on the host. */
+ memcpy (((char *) &s) + offset, location, count);
+
+ tdata->gp = s.gp_value;
+ tdata->gprmask = s.gprmask;
+ for (i = 0; i < 4; i++)
+ tdata->cprmask[i] = s.cprmask[i];
+ tdata->fprmask = s.fprmask;
+
+ return true;
+
+ }
+
+ bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET);
+
+ if (count != 0)
+ return (bfd_write (location, 1, count, abfd) == count) ? true : false;
+
+ return true;
+}
+
+/* Write out an ECOFF file. */
+
+boolean
+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->external_hdr_size;
+ const bfd_size_type external_reloc_size = backend->external_reloc_size;
+ void (* const swap_reloc_out) PARAMS ((bfd *,
+ const struct internal_reloc *,
+ PTR))
+ = backend->swap_reloc_out;
+ asection *current;
+ unsigned int count;
+ file_ptr scn_base;
+ file_ptr reloc_base;
+ file_ptr sym_base;
+ unsigned long reloc_size;
+ unsigned long text_size;
+ unsigned long text_start;
+ unsigned long data_size;
+ unsigned long data_start;
+ unsigned long bss_size;
+ PTR buff;
+ struct internal_filehdr internal_f;
+ struct internal_aouthdr internal_a;
+ int i;
+
+ bfd_error = system_call_error;
+
+ if(abfd->output_has_begun == false)
+ ecoff_compute_section_file_positions(abfd);
+
+ if (abfd->sections != (asection *) NULL)
+ scn_base = abfd->sections->filepos;
+ else
+ scn_base = 0;
+ reloc_base = ecoff_data (abfd)->reloc_filepos;
+
+ count = 1;
+ reloc_size = 0;
+ for (current = abfd->sections;
+ current != (asection *)NULL;
+ current = current->next)
+ {
+ if (strcmp (current->name, SCOMMON) == 0
+ || strcmp (current->name, REGINFO) == 0)
+ continue;
+ current->target_index = count;
+ ++count;
+ if (current->reloc_count != 0)
+ {
+ bfd_size_type relsize;
+
+ current->rel_filepos = reloc_base;
+ relsize = current->reloc_count * external_reloc_size;
+ reloc_size += relsize;
+ reloc_base += relsize;
+ }
+ else
+ current->rel_filepos = 0;
+ }
+
+ sym_base = reloc_base + 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 + round - 1) &~ (round - 1);
+
+ ecoff_data (abfd)->sym_filepos = sym_base;
+
+ if ((abfd->flags & D_PAGED) != 0)
+ text_size = ecoff_sizeof_headers (abfd, false);
+ else
+ text_size = 0;
+ text_start = 0;
+ data_size = 0;
+ data_start = 0;
+ bss_size = 0;
+
+ /* Write section headers to the file. */
+
+ buff = (PTR) alloca (scnhsz);
+ internal_f.f_nscns = 0;
+ if (bfd_seek (abfd, (file_ptr) (filhsz + aoutsz), SEEK_SET) != 0)
+ return false;
+ for (current = abfd->sections;
+ current != (asection *) NULL;
+ current = current->next)
+ {
+ struct internal_scnhdr section;
+ bfd_vma vma;
+
+ if (strcmp (current->name, SCOMMON) == 0)
+ {
+ BFD_ASSERT (bfd_get_section_size_before_reloc (current) == 0
+ && current->reloc_count == 0);
+ continue;
+ }
+ if (strcmp (current->name, REGINFO) == 0)
+ {
+ BFD_ASSERT (current->reloc_count == 0);
+ continue;
+ }
+
+ ++internal_f.f_nscns;
+
+ strncpy (section.s_name, current->name, sizeof section.s_name);
+
+ /* FIXME: is this correct for shared libraries? I think it is
+ but I have no platform to check. Ian Lance Taylor. */
+ 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. */
+ section.s_lnnoptr = 0;
+
+ 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)
+ return false;
+
+ if ((section.s_flags & STYP_TEXT) != 0)
+ {
+ text_size += bfd_get_section_size_before_reloc (current);
+ if (text_start == 0 || text_start > vma)
+ text_start = vma;
+ }
+ else if ((section.s_flags & STYP_RDATA) != 0
+ || (section.s_flags & STYP_DATA) != 0
+ || (section.s_flags & STYP_LIT8) != 0
+ || (section.s_flags & STYP_LIT4) != 0
+ || (section.s_flags & STYP_SDATA) != 0)
+ {
+ data_size += bfd_get_section_size_before_reloc (current);
+ if (data_start == 0 || data_start > vma)
+ data_start = vma;
+ }
+ else if ((section.s_flags & STYP_BSS) != 0
+ || (section.s_flags & STYP_SBSS) != 0)
+ bss_size += bfd_get_section_size_before_reloc (current);
+ }
+
+ /* 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 = sym_base;
+ }
+ 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: This is what Ultrix puts in, and it makes the Ultrix
+ linker happy. But, is it right? */
+ internal_a.vstamp = 0x20a;
+
+ /* 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)
+ return false;
+
+ buff = (PTR) alloca (filhsz);
+ bfd_coff_swap_filehdr_out (abfd, (PTR) &internal_f, buff);
+ if (bfd_write (buff, 1, filhsz, abfd) != filhsz)
+ return false;
+
+ buff = (PTR) alloca (aoutsz);
+ bfd_coff_swap_aouthdr_out (abfd, (PTR) &internal_a, buff);
+ if (bfd_write (buff, 1, aoutsz, abfd) != aoutsz)
+ return false;
+
+ /* 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;
+
+ buff = bfd_alloc (abfd, current->reloc_count * external_reloc_size);
+ if (buff == NULL)
+ {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ reloc_ptr_ptr = current->orelocation;
+ reloc_end = reloc_ptr_ptr + current->reloc_count;
+ out_ptr = (char *) buff;
+ for (;
+ reloc_ptr_ptr < reloc_end;
+ reloc_ptr_ptr++, out_ptr += external_reloc_size)
+ {
+ arelent *reloc;
+ asymbol *sym;
+ struct internal_reloc in;
+
+ memset (&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
+ abort ();
+ in.r_extern = 0;
+ }
+
+ (*swap_reloc_out) (abfd, &in, (PTR) out_ptr);
+ }
+
+ if (bfd_seek (abfd, current->rel_filepos, SEEK_SET) != 0)
+ return false;
+ if (bfd_write (buff, external_reloc_size, current->reloc_count, abfd)
+ != external_reloc_size * current->reloc_count)
+ return false;
+ bfd_release (abfd, buff);
+ }
+
+ /* Write out the symbolic debugging information. */
+ if (bfd_get_symcount (abfd) > 0)
+ {
+ HDRR *symhdr;
+ unsigned long sym_offset;
+
+ /* Set up the offsets in the symbolic header. */
+ symhdr = &ecoff_data (abfd)->symbolic_header;
+ sym_offset = ecoff_data (abfd)->sym_filepos + external_hdr_size;
+
+#define SET(offset, size, ptr) \
+ if (symhdr->size == 0) \
+ symhdr->offset = 0; \
+ else \
+ symhdr->offset = (((char *) ecoff_data (abfd)->ptr \
+ - (char *) ecoff_data (abfd)->raw_syments) \
+ + sym_offset);
+
+ SET (cbLineOffset, cbLine, line);
+ SET (cbDnOffset, idnMax, external_dnr);
+ SET (cbPdOffset, ipdMax, external_pdr);
+ SET (cbSymOffset, isymMax, external_sym);
+ SET (cbOptOffset, ioptMax, external_opt);
+ SET (cbAuxOffset, iauxMax, external_aux);
+ SET (cbSsOffset, issMax, ss);
+ SET (cbSsExtOffset, issExtMax, ssext);
+ SET (cbFdOffset, ifdMax, external_fdr);
+ SET (cbRfdOffset, crfd, external_rfd);
+ SET (cbExtOffset, iextMax, external_ext);
+#undef SET
+
+ if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos,
+ SEEK_SET) != 0)
+ return false;
+ buff = (PTR) alloca (external_hdr_size);
+ (*backend->swap_hdr_out) (abfd, &ecoff_data (abfd)->symbolic_header,
+ buff);
+ if (bfd_write (buff, 1, external_hdr_size, abfd) != external_hdr_size)
+ return false;
+ if (bfd_write ((PTR) ecoff_data (abfd)->raw_syments, 1,
+ ecoff_data (abfd)->raw_size, abfd)
+ != ecoff_data (abfd)->raw_size)
+ return false;
+ }
+ else if ((abfd->flags & EXEC_P) != 0
+ && (abfd->flags & D_PAGED) != 0)
+ {
+ char c;
+
+ /* A demand paged executable must occupy an even number of
+ pages. */
+ if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1,
+ SEEK_SET) != 0)
+ return false;
+ 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)
+ return false;
+ if (bfd_write (&c, 1, 1, abfd) != 1)
+ return false;
+ }
+
+ return true;
+}
+
+/* Archive handling. ECOFF uses what appears to be a unique type of
+ archive header (which I call an 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.
+
+ We could use the hash table when looking up symbols in a library.
+ This would require a new BFD target entry point to replace the
+ bfd_get_next_mapent function used by the linker.
+
+ 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
+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;
+
+ bfd_seek (abfd, (file_ptr) -16, SEEK_CUR);
+
+ /* 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_error = wrong_format;
+ return false;
+ }
+
+ /* Read in the armap. */
+ ardata = bfd_ardata (abfd);
+ mapdata = 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_error = no_memory;
+ return false;
+ }
+
+ if (bfd_read ((PTR) raw_armap, 1, parsed_size, abfd) != parsed_size)
+ {
+ bfd_error = malformed_archive;
+ bfd_release (abfd, (PTR) raw_armap);
+ return false;
+ }
+
+ 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)));
+ 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
+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] = '\n';
+
+ /* 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, hashsize, temp);
+ if (bfd_write (temp, 1, 4, abfd) != 4)
+ return false;
+
+ hashtable = (bfd_byte *) bfd_zalloc (abfd, symdefsize);
+
+ 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, map[i].namidx, (PTR) (hashtable + hash * 8));
+ bfd_h_put_32 (abfd, firstreal, (PTR) (hashtable + hash * 8 + 4));
+ }
+
+ if (bfd_write (hashtable, 1, symdefsize, abfd) != symdefsize)
+ return false;
+
+ bfd_release (abfd, hashtable);
+
+ /* Now write the strings. */
+ bfd_h_put_32 (abfd, stringsize, temp);
+ if (bfd_write (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 ("\0", 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. */
+
+bfd_target *
+ecoff_archive_p (abfd)
+ bfd *abfd;
+{
+ char armag[SARMAG + 1];
+
+ if (bfd_read ((PTR) armag, 1, SARMAG, abfd) != SARMAG
+ || strncmp (armag, ARMAG, SARMAG) != 0)
+ {
+ bfd_error = wrong_format;
+ return (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_error = no_memory;
+ return (bfd_target *) NULL;
+ }
+
+ bfd_ardata (abfd)->first_file_filepos = SARMAG;
+
+ if (ecoff_slurp_armap (abfd) == false
+ || ecoff_slurp_extended_name_table (abfd) == false)
+ {
+ bfd_release (abfd, bfd_ardata (abfd));
+ abfd->tdata.aout_ar_data = (struct artdata *) NULL;
+ return (bfd_target *) NULL;
+ }
+
+ return abfd->xvec;
+}
diff --git a/gnu/usr.bin/gdb/bfd/elf.c b/gnu/usr.bin/gdb/bfd/elf.c
new file mode 100644
index 0000000..2fcf2f1
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/elf.c
@@ -0,0 +1,248 @@
+/* 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 "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
+DEFUN (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 *
+DEFUN (elf_read, (abfd, offset, size),
+ bfd * abfd AND
+ long offset AND
+ int size)
+{
+ char *buf;
+
+ if ((buf = bfd_alloc (abfd, size)) == NULL)
+ {
+ bfd_error = no_memory;
+ return NULL;
+ }
+ if (bfd_seek (abfd, offset, SEEK_SET) == -1)
+ {
+ bfd_error = system_call_error;
+ return NULL;
+ }
+ if (bfd_read ((PTR) buf, size, 1, abfd) != size)
+ {
+ bfd_error = system_call_error;
+ return NULL;
+ }
+ return buf;
+}
+
+boolean
+DEFUN (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_error = no_memory;
+ return false;
+ }
+ /* since everything is done at close time, do we need any
+ initialization? */
+
+ return true;
+}
+
+char *
+DEFUN (elf_get_str_section, (abfd, shindex),
+ bfd * abfd AND
+ 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 *
+DEFUN (elf_string_from_elf_section, (abfd, shindex, strindex),
+ bfd * abfd AND
+ unsigned int shindex AND
+ 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;
+}
+
+/*
+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 *
+DEFUN (bfd_elf_find_section, (abfd, name),
+ bfd * abfd AND
+ 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 struct bfd_elf_arch_map bfd_elf_arch_map[] = {
+ { bfd_arch_sparc, EM_SPARC },
+ { bfd_arch_i386, EM_386 },
+ { bfd_arch_m68k, EM_68K },
+ { bfd_arch_m88k, EM_88K },
+ { bfd_arch_i860, EM_860 },
+ { bfd_arch_mips, EM_MIPS },
+ { bfd_arch_hppa, EM_HPPA },
+};
+
+const int bfd_elf_arch_map_size = sizeof (bfd_elf_arch_map) / sizeof (bfd_elf_arch_map[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. */
+
+bfd_reloc_status_type
+bfd_elf_generic_reloc (abfd,
+ reloc_entry,
+ symbol,
+ data,
+ input_section,
+ output_bfd)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+{
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && reloc_entry->addend == 0)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ return bfd_reloc_continue;
+}
diff --git a/gnu/usr.bin/gdb/bfd/format.c b/gnu/usr.bin/gdb/bfd/format.c
new file mode 100644
index 0000000..6a80ed7
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/format.c
@@ -0,0 +1,258 @@
+/* Generic BFD support for file formats.
+ Copyright (C) 1990-1991 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. 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"
+
+extern bfd_target *target_vector[];
+extern bfd_target *default_vector[];
+
+
+/*
+FUNCTION
+ bfd_check_format
+
+SYNOPSIS
+ boolean bfd_check_format(bfd *abfd, bfd_format format);
+
+DESCRIPTION
+ This routine is supplied a BFD and a format. It attempts to
+ verify if the file attached to the BFD is indeed compatible
+ with the format specified (ie, one of <<bfd_object>>,
+ <<bfd_archive>> or <<bfd_core>>).
+
+ If the BFD has been set to a specific @var{target} before the
+ call, only the named target and format combination will be
+ checked. If the target has not been set, or has been set to
+ <<default>> then all the known target backends will be
+ 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 invalid_operation -
+ if <<format>> is not one of <<bfd_object>>, <<bfd_archive>> or
+ <<bfd_core>>.
+
+ o system_call_error -
+ if an error occured during a read - even some file mismatches
+ can cause system_call_errors
+
+ o file_not_recognised -
+ none of the backends recognised the file format
+
+ o file_ambiguously_recognized -
+ more than one backend recognised the file format.
+
+*/
+
+boolean
+DEFUN(bfd_check_format,(abfd, format),
+ bfd *abfd AND
+ bfd_format format)
+{
+ bfd_target **target, *save_targ, *right_targ;
+ int match_count;
+
+ if (!bfd_read_p (abfd) ||
+ ((int)(abfd->format) < (int)bfd_unknown) ||
+ ((int)(abfd->format) >= (int)bfd_type_end)) {
+ 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;
+ 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) {
+ bfd_seek (abfd, (file_ptr)0, SEEK_SET); /* rewind! */
+
+ right_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
+ if (right_targ) {
+ abfd->xvec = right_targ; /* Set the target as returned */
+ return true; /* File position has moved, BTW */
+ }
+ }
+
+ for (target = target_vector; *target != NULL; target++) {
+ bfd_target *temp;
+
+ abfd->xvec = *target; /* Change BFD's target temporarily */
+ bfd_seek (abfd, (file_ptr)0, SEEK_SET);
+ /* If _bfd_check_format neglects to set bfd_error, assume 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_error = wrong_format;
+ temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
+ if (temp) { /* This format checks out as ok! */
+ right_targ = temp;
+ 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 == default_vector[0])
+ {
+ 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_error != wrong_format) {
+ abfd->xvec = save_targ;
+ abfd->format = bfd_unknown;
+ return false;
+ }
+ }
+
+ if (match_count == 1) {
+ abfd->xvec = right_targ; /* Change BFD's target permanently */
+ return true; /* File position has moved, BTW */
+ }
+
+ abfd->xvec = save_targ; /* Restore original target type */
+ abfd->format = bfd_unknown; /* Restore original format */
+ bfd_error = ((match_count == 0) ? file_not_recognized :
+ file_ambiguously_recognized);
+ return false;
+}
+
+
+/*
+FUNCTION
+ bfd_set_format
+
+SYNOPSIS
+ boolean bfd_set_format(bfd *, bfd_format);
+
+DESCRIPTION
+ This function sets the file format of the supplied BFD to the
+ format requested. If the target set in the BFD does not
+ support the format requested, the format is illegal or the BFD
+ is not open for writing than an error occurs.
+
+*/
+
+boolean
+DEFUN(bfd_set_format,(abfd, format),
+ bfd *abfd AND
+ bfd_format format)
+{
+
+ if (bfd_read_p (abfd) ||
+ ((int)abfd->format < (int)bfd_unknown) ||
+ ((int)abfd->format >= (int)bfd_type_end)) {
+ 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);
+
+DESCRIPTION
+ This function takes one argument, and enumerated type
+ (bfd_format) and returns a pointer to a const string
+ <<invalid>>, <<object>>, <<archive>>, <<core>> or <<unknown>>
+ depending upon the value of the enumeration.
+*/
+
+CONST char *
+DEFUN(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..22cbd6a
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/freebsd386.c
@@ -0,0 +1,110 @@
+/* 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
+
+#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/init.c b/gnu/usr.bin/gdb/bfd/init.c
new file mode 100644
index 0000000..30a2759
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/init.c
@@ -0,0 +1,78 @@
+/* bfd initialization stuff
+ Copyright (C) 1990-1991 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 DEFUN_VOID (bfd_section_init);
+
+static boolean initialized = false;
+
+/*
+SECTION
+ Initialization
+
+ This is the initialization section
+
+*/
+
+/*
+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 DEFUN_VOID(bfd_init)
+{
+ if (initialized == false) {
+ initialized = true;
+
+ bfd_arch_init();
+ }
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_check_init
+
+DESCRIPTION
+ This routine is called before any other bfd function using
+ initialized data is used to ensure that the structures have
+ been initialized. Soon this function will go away, and the bfd
+ library will assume that bfd_init has been called.
+
+SYNOPSIS
+ void bfd_check_init(void);
+*/
+
+void DEFUN_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..0d99d0c
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libaout.h
@@ -0,0 +1,393 @@
+/* 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. */
+
+/* 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. */
+
+/* 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 these types at file level, since they are used in parameter
+ lists, which have wierd scope. */
+struct external_exec;
+struct internal_exec;
+
+/* 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;
+
+ /* 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;
+};
+#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 */
+ M_386 = 100,
+ M_29K = 101, /* AMD 29000 */
+ M_386_DYNIX = 102, /* Sequent running dynix */
+ M_386_NETBSD = 134, /* NetBSD/386 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 & 0x8000000)
+
+#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_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;
+
+ unsigned exec_bytes_size;
+ unsigned vma_adjusted : 1;
+
+ /* used when a bfd supports several highly similar formats */
+ enum {
+ default_format = 0,
+ gnu_encap_format } subformat;
+
+ enum {
+ undecided_magic = 0,
+ z_magic,
+ o_magic,
+ n_magic } magic;
+};
+
+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)
+
+/* 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))
+
+/* Prototype declarations for functions defined in aoutx.h */
+
+boolean
+NAME(aout,squirt_out_relocs) PARAMS ((bfd *abfd, asection *section));
+
+bfd_target *
+NAME(aout,some_aout_object_p) PARAMS ((bfd *abfd,
+ struct internal_exec *execp,
+ 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
+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,slurp_symbol_table) PARAMS ((bfd *abfd));
+
+void
+NAME(aout,write_syms) PARAMS ((bfd *abfd));
+
+void
+NAME(aout,reclaim_symbol_table) PARAMS ((bfd *abfd));
+
+unsigned int
+NAME(aout,get_symtab_upper_bound) PARAMS ((bfd *abfd));
+
+unsigned int
+NAME(aout,get_symtab) PARAMS ((bfd *abfd, asymbol **location));
+
+boolean
+NAME(aout,slurp_reloc_table) PARAMS ((bfd *abfd, sec_ptr asect,
+ asymbol **symbols));
+
+unsigned int
+NAME(aout,canonicalize_reloc) PARAMS ((bfd *abfd, sec_ptr section,
+ arelent **relptr, asymbol **symbols));
+
+unsigned int
+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,close_and_cleanup) PARAMS ((bfd *abfd));
+
+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));
+
+/* 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_32_close_and_cleanup bfd_generic_close_and_cleanup
+
+#define aout_64_get_section_contents bfd_generic_get_section_contents
+#define aout_64_close_and_cleanup bfd_generic_close_and_cleanup
+#ifndef NO_WRITE_HEADER_KLUDGE
+#define NO_WRITE_HEADER_KLUDGE 0
+#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); \
+ \
+ bfd_seek (abfd, (file_ptr) 0, SEEK_SET); \
+ bfd_write ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd); \
+ /* Now write out reloc info, followed by syms and strings */ \
+ \
+ if (bfd_get_symcount (abfd) != 0) \
+ { \
+ bfd_seek (abfd, (file_ptr)(N_SYMOFF(*execp)), SEEK_SET); \
+ \
+ NAME(aout,write_syms)(abfd); \
+ \
+ bfd_seek (abfd, (file_ptr)(N_TRELOFF(*execp)), SEEK_SET); \
+ \
+ if (!NAME(aout,squirt_out_relocs) (abfd, obj_textsec (abfd))) return false; \
+ bfd_seek (abfd, (file_ptr)(N_DRELOFF(*execp)), SEEK_SET); \
+ \
+ if (!NAME(aout,squirt_out_relocs)(abfd, obj_datasec (abfd))) return false; \
+ } \
+ }
+#endif
diff --git a/gnu/usr.bin/gdb/bfd/libbfd.c b/gnu/usr.bin/gdb/bfd/libbfd.c
new file mode 100644
index 0000000..1bf8f7f
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libbfd.c
@@ -0,0 +1,850 @@
+/* Assorted BFD support routines, only used internally.
+ 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. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+/*
+SECTION
+ libbfd
+
+DESCRIPTION
+ This file contains various routines which are used within BFD.
+ They are not intended for export, but are documented here for
+ completeness.
+*/
+
+boolean
+DEFUN(_bfd_dummy_new_section_hook,(ignore, ignore_newsect),
+ bfd *ignore AND
+ asection *ignore_newsect)
+{
+ return true;
+}
+
+boolean
+DEFUN(bfd_false ,(ignore),
+ bfd *ignore)
+{
+ return false;
+}
+
+boolean
+DEFUN(bfd_true,(ignore),
+ bfd *ignore)
+{
+ return true;
+}
+
+PTR
+DEFUN(bfd_nullvoidptr,(ignore),
+ bfd *ignore)
+{
+ return (PTR)NULL;
+}
+
+int
+DEFUN(bfd_0,(ignore),
+ bfd *ignore)
+{
+ return 0;
+}
+
+unsigned int
+DEFUN(bfd_0u,(ignore),
+ bfd *ignore)
+{
+ return 0;
+}
+
+void
+DEFUN(bfd_void,(ignore),
+ bfd *ignore)
+{
+}
+
+boolean
+DEFUN(_bfd_dummy_core_file_matches_executable_p,(ignore_core_bfd, ignore_exec_bfd),
+ bfd *ignore_core_bfd AND
+ bfd *ignore_exec_bfd)
+{
+ bfd_error = invalid_operation;
+ return false;
+}
+
+/* of course you can't initialize a function to be the same as another, grr */
+
+char *
+DEFUN(_bfd_dummy_core_file_failing_command,(ignore_abfd),
+ bfd *ignore_abfd)
+{
+ return (char *)NULL;
+}
+
+int
+DEFUN(_bfd_dummy_core_file_failing_signal,(ignore_abfd),
+ bfd *ignore_abfd)
+{
+ return 0;
+}
+
+bfd_target *
+DEFUN(_bfd_dummy_target,(ignore_abfd),
+ bfd *ignore_abfd)
+{
+ return 0;
+}
+
+/** zalloc -- allocate and clear storage */
+
+
+#ifndef zalloc
+char *
+DEFUN(zalloc,(size),
+ bfd_size_type size)
+{
+ char *ptr = (char *) malloc ((size_t)size);
+
+ if ((ptr != NULL) && (size != 0))
+ memset(ptr,0, (size_t) size);
+
+ return ptr;
+}
+#endif
+
+/*
+INTERNAL_FUNCTION
+ bfd_xmalloc
+
+SYNOPSIS
+ PTR bfd_xmalloc( bfd_size_type size);
+
+DESCRIPTION
+ Like malloc, but exit if no more memory.
+
+*/
+
+/** There is major inconsistency in how running out of memory is handled.
+ Some routines return a NULL, and set bfd_error to no_memory.
+ However, obstack routines can't do this ... */
+
+
+DEFUN(PTR bfd_xmalloc,(size),
+ bfd_size_type size)
+{
+ static CONST char no_memory_message[] = "Virtual memory exhausted!\n";
+ PTR ptr;
+ if (size == 0) size = 1;
+ ptr = (PTR)malloc((size_t) size);
+ if (!ptr)
+ {
+ write (2, no_memory_message, sizeof(no_memory_message)-1);
+ exit (-1);
+ }
+ return ptr;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_xmalloc_by_size_t
+
+SYNOPSIS
+ PTR bfd_xmalloc_by_size_t ( size_t size);
+
+DESCRIPTION
+ Like malloc, but exit if no more memory.
+ Uses size_t, so it's suitable for use as obstack_chunk_alloc.
+ */
+PTR
+DEFUN(bfd_xmalloc_by_size_t, (size),
+ size_t size)
+{
+ return bfd_xmalloc ((bfd_size_type) size);
+}
+
+/* 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 DEFUN(real_read,(where, a,b, file),
+ PTR where AND
+ int a AND
+ int b AND
+ FILE *file)
+{
+ return fread(where, a,b,file);
+}
+bfd_size_type
+DEFUN(bfd_read,(ptr, size, nitems, abfd),
+ PTR ptr AND
+ bfd_size_type size AND
+ bfd_size_type nitems AND
+ 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
+ return nread;
+}
+
+bfd_size_type
+DEFUN(bfd_write,(ptr, size, nitems, abfd),
+ CONST PTR ptr AND
+ bfd_size_type size AND
+ bfd_size_type nitems AND
+ 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
+ return nwrote;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_write_bigendian_4byte_int
+
+SYNOPSIS
+ void bfd_write_bigendian_4byte_int(bfd *abfd, int i);
+
+DESCRIPTION
+ Writes a 4 byte integer to the outputing bfd, in big endian
+ mode regardless of what else is going on. This is useful in
+ archives.
+
+*/
+void
+DEFUN(bfd_write_bigendian_4byte_int,(abfd, i),
+ bfd *abfd AND
+ int i)
+{
+ bfd_byte buffer[4];
+ bfd_putb32(i, buffer);
+ bfd_write((PTR)buffer, 4, 1, abfd);
+}
+
+long
+DEFUN(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
+DEFUN(bfd_flush,(abfd),
+ bfd *abfd)
+{
+ return fflush (bfd_cache_lookup(abfd));
+}
+
+int
+DEFUN(bfd_stat,(abfd, statbuf),
+ bfd *abfd AND
+ struct stat *statbuf)
+{
+ return fstat (fileno(bfd_cache_lookup(abfd)), statbuf);
+}
+
+int
+DEFUN(bfd_seek,(abfd, position, direction),
+ bfd * CONST abfd AND
+ CONST file_ptr position AND
+ 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)
+ {
+#ifndef NDEBUG
+ /* 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);
+ 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
+DEFUN(bfd_add_to_string_table,(table, new_string, table_length, free_ptr),
+ char **table AND
+ char *new_string AND
+ unsigned int *table_length AND
+ 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 = zalloc ((bfd_size_type) space_length);
+
+ if (base == NULL) {
+ 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_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 libaout.h defines GET_WORD to
+ either bfd_get_32 or bfd_get_64.
+
+ In the put routines, 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
+FUNCTION
+ bfd_h_get_size
+
+DESCRIPTION
+ These macros have the same function as their <<bfd_get_x>>
+ bretherin, 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 (((HOST_64_BIT)0x80000000) << 32)
+#define COERCE64(x) \
+ (((bfd_signed_vma) (x) ^ EIGHT_GAZILLION) - EIGHT_GAZILLION)
+
+bfd_vma
+DEFUN(bfd_getb16,(addr),
+ register bfd_byte *addr)
+{
+ return (addr[0] << 8) | addr[1];
+}
+
+bfd_vma
+DEFUN(bfd_getl16,(addr),
+ register bfd_byte *addr)
+{
+ return (addr[1] << 8) | addr[0];
+}
+
+bfd_signed_vma
+DEFUN(bfd_getb_signed_16,(addr),
+ register bfd_byte *addr)
+{
+ return COERCE16((addr[0] << 8) | addr[1]);
+}
+
+bfd_signed_vma
+DEFUN(bfd_getl_signed_16,(addr),
+ register bfd_byte *addr)
+{
+ return COERCE16((addr[1] << 8) | addr[0]);
+}
+
+void
+DEFUN(bfd_putb16,(data, addr),
+ bfd_vma data AND
+ register bfd_byte *addr)
+{
+ addr[0] = (bfd_byte)(data >> 8);
+ addr[1] = (bfd_byte )data;
+}
+
+void
+DEFUN(bfd_putl16,(data, addr),
+ bfd_vma data AND
+ register bfd_byte *addr)
+{
+ addr[0] = (bfd_byte )data;
+ addr[1] = (bfd_byte)(data >> 8);
+}
+
+bfd_vma
+bfd_getb32 (addr)
+ register bfd_byte *addr;
+{
+ return (((((bfd_vma)addr[0] << 8) | addr[1]) << 8)
+ | addr[2]) << 8 | addr[3];
+}
+
+bfd_vma
+bfd_getl32 (addr)
+ register 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 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 bfd_byte *addr;
+{
+ return COERCE32((((((bfd_vma)addr[3] << 8) | addr[2]) << 8)
+ | addr[1]) << 8 | addr[0]);
+}
+
+bfd_vma
+DEFUN(bfd_getb64,(addr),
+ register 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
+DEFUN(bfd_getl64,(addr),
+ register 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
+DEFUN(bfd_getb_signed_64,(addr),
+ register 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
+DEFUN(bfd_getl_signed_64,(addr),
+ register 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
+DEFUN(bfd_putb32,(data, addr),
+ bfd_vma data AND
+ 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
+DEFUN(bfd_putl32,(data, addr),
+ bfd_vma data AND
+ 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
+DEFUN(bfd_putb64,(data, addr),
+ bfd_vma data AND
+ 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
+DEFUN(bfd_putl64,(data, addr),
+ bfd_vma data AND
+ 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
+DEFUN(bfd_generic_get_section_contents, (abfd, section, location, offset, count),
+ bfd *abfd AND
+ sec_ptr section AND
+ PTR location AND
+ file_ptr offset AND
+ 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
+DEFUN(bfd_generic_set_section_contents, (abfd, section, location, offset, count),
+ bfd *abfd AND
+ sec_ptr section AND
+ PTR location AND
+ file_ptr offset AND
+ bfd_size_type count)
+{
+ if (count == 0)
+ return true;
+ if ((bfd_size_type)(offset+count) > bfd_get_section_size_after_reloc(section)
+ || bfd_seek(abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1
+ || bfd_write(location, (bfd_size_type)1, count, abfd) != count)
+ return (false); /* on error */
+ return (true);
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_log2
+
+DESCRIPTION
+ Return the log base 2 of the value supplied, rounded up. eg an
+ arg of 1025 would return 11.
+
+SYNOPSIS
+ unsigned int bfd_log2(bfd_vma x);
+*/
+
+unsigned
+bfd_log2(x)
+ bfd_vma x;
+{
+ unsigned result = 0;
+ while ( (bfd_vma)(1<< result) < x)
+ result++;
+ return result;
+}
diff --git a/gnu/usr.bin/gdb/bfd/libbfd.h b/gnu/usr.bin/gdb/bfd/libbfd.h
new file mode 100644
index 0000000..fcd5bbc
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libbfd.h
@@ -0,0 +1,273 @@
+/* libbfd.h -- Declarations used by bfd library *implementation*.
+ (This include file is not for users of the library.)
+ 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. */
+
+
+/* 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 */
+ time_t 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. */
+};
+
+#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 *zalloc 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 new));
+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 * look_for_bfd_in_cache PARAMS ((bfd *arch_bfd, file_ptr index));
+boolean _bfd_generic_mkarchive PARAMS ((bfd *abfd));
+struct areltdata * snarf_ar_hdr PARAMS ((bfd *abfd));
+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 * new_bfd PARAMS (());
+
+#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));
+void bfd_void PARAMS ((bfd *ignore));
+
+bfd * new_bfd_contained_in PARAMS ((bfd *));
+boolean _bfd_dummy_new_section_hook PARAMS ((bfd *ignore, asection *newsect));
+char * _bfd_dummy_core_file_failing_command PARAMS ((bfd *abfd));
+int _bfd_dummy_core_file_failing_signal PARAMS ((bfd *abfd));
+boolean _bfd_dummy_core_file_matches_executable_p PARAMS ((bfd *core_bfd,
+ bfd *exec_bfd));
+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 *));
+
+boolean bfd_generic_get_section_contents PARAMS ((bfd *abfd, sec_ptr section,
+ PTR location, file_ptr offset,
+ bfd_size_type count));
+
+boolean bfd_generic_set_section_contents PARAMS ((bfd *abfd, sec_ptr section,
+ PTR location, file_ptr offset,
+ bfd_size_type count));
+
+/* 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
+
+/* Generic routine for close_and_cleanup is really just bfd_true. */
+#define bfd_generic_close_and_cleanup bfd_true
+
+/* And more follows */
+
+void
+bfd_check_init PARAMS ((void));
+
+PTR
+bfd_xmalloc PARAMS (( bfd_size_type size));
+
+PTR
+bfd_xmalloc_by_size_t PARAMS (( size_t size));
+
+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_close PARAMS ((bfd *));
+
+FILE*
+bfd_open_file PARAMS ((bfd *));
+
+FILE *
+bfd_cache_lookup_worker PARAMS ((bfd *));
+
+void
+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 AND
+ bfd_reloc_code_real_type code));
+
+boolean
+bfd_generic_relax_section
+ PARAMS ((bfd *abfd,
+ asection *section,
+ asymbol **symbols));
+
+bfd_byte *
+
+bfd_generic_get_relocated_section_contents PARAMS ((bfd *abfd,
+ struct bfd_seclet *seclet,
+ bfd_byte *data,
+ boolean relocateable));
+
+boolean
+bfd_generic_seclet_link
+ PARAMS ((bfd *abfd,
+ PTR data,
+ boolean relocateable));
+
+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 *));
+
+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 *, CONST char *));
+
+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..2aa6ad4
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libcoff.h
@@ -0,0 +1,352 @@
+/* BFD COFF object file private structure.
+ 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. */
+
+
+/* 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 bfd_target *coff_object_p PARAMS ((bfd *));
+extern struct sec *coff_section_from_bfd_index PARAMS ((bfd *, int));
+extern unsigned int coff_get_symtab_upper_bound PARAMS ((bfd *));
+extern unsigned int 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 void coff_renumber_symbols PARAMS ((bfd *));
+extern void coff_mangle_symbols PARAMS ((bfd *));
+extern void coff_write_symbols PARAMS ((bfd *));
+extern void 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 unsigned int 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 *,
+ asymbol **));
+extern bfd_byte *bfd_coff_reloc16_get_relocated_section_contents
+ PARAMS ((bfd *, struct bfd_seclet *, bfd_byte *, boolean relocateable));
+extern bfd_vma bfd_coff_reloc16_get_value PARAMS ((arelent *,
+ struct bfd_seclet *));
+
+/* 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 tag field of this symbol be renumbered.
+ Created by coff_pointerize_aux. */
+char fix_tag;
+
+ /* Should the endidx field of this symbol be renumbered.
+ Created by coff_pointerize_aux. */
+char fix_end;
+
+ /* 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 ,
+ 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,
+ 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_seclet *seclet,
+ arelent *reloc,
+ bfd_byte *data,
+ unsigned int *src_ptr,
+ unsigned int *dst_ptr));
+ int (*_bfd_coff_reloc16_estimate) PARAMS ((
+ asection *input_section,
+ asymbol **symbols,
+ arelent *r,
+ unsigned int shrink));
+
+} 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,i) \
+ ((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,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(abfd, i, t,c,o) \
+ ((coff_backend_info (abfd)->_bfd_coff_swap_aux_out) (abfd, i,t,c, 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, seclet, reloc, data, src_ptr, dst_ptr)\
+ ((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\
+ (abfd, seclet, reloc, data, src_ptr, dst_ptr))
+
+#define bfd_coff_reloc16_estimate(abfd, section, symbols, reloc, shrink)\
+ ((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\
+ (section, symbols, reloc, shrink))
+
+
diff --git a/gnu/usr.bin/gdb/bfd/libecoff.h b/gnu/usr.bin/gdb/bfd/libecoff.h
new file mode 100644
index 0000000..ad3e8f2
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libecoff.h
@@ -0,0 +1,265 @@
+/* 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. */
+
+/* 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;
+ /* Symbol table magic number. */
+ int sym_magic;
+ /* Initial portion of armap string. */
+ const char *armap_start;
+ /* Alignment of debugging information. E.g., 4. */
+ bfd_size_type debug_align;
+ /* The page boundary used to align sections in a demand-paged
+ executable file. E.g., 0x1000. */
+ bfd_vma round;
+ /* Bitsize of constructor entries. */
+ unsigned int constructor_bitsize;
+ /* Reloc to use for constructor entries. */
+ CONST struct reloc_howto_struct *constructor_reloc;
+ /* 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 *));
+ /* 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));
+ /* It so happens that the auxiliary type information has the same
+ type and format for all known ECOFF targets. I don't see any
+ reason that that should change, so at least for now the auxiliary
+ swapping information is not in this table. */
+ /* 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 (*finish_reloc) PARAMS ((bfd *, struct internal_reloc *, arelent *));
+};
+
+/* 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 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 size of the unswapped ECOFF symbolic information. */
+ bfd_size_type raw_size;
+
+ /* The unswapped ECOFF symbolic information. */
+ PTR raw_syments;
+
+ /* The swapped ECOFF symbolic header. */
+ HDRR symbolic_header;
+
+ /* Pointers to the unswapped symbolic 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 */
+
+ /* The swapped FDR information. */
+ FDR *fdr;
+
+ /* The FDR index. This is set for an input BFD to a link so that
+ the external symbols can set their FDR index correctly. */
+ unsigned int ifdbase;
+
+ /* The canonical BFD symbols. */
+ struct ecoff_symbol_struct *canonical_symbols;
+
+} 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))
+
+/* Make an ECOFF object. */
+extern boolean ecoff_mkobject PARAMS ((bfd *));
+
+/* Read in the ECOFF symbolic debugging information. */
+extern boolean ecoff_slurp_symbolic_info PARAMS ((bfd *));
+
+/* Generic ECOFF BFD backend vectors. */
+extern asymbol *ecoff_make_empty_symbol PARAMS ((bfd *abfd));
+extern unsigned int ecoff_get_symtab_upper_bound PARAMS ((bfd *abfd));
+extern unsigned int ecoff_get_symtab PARAMS ((bfd *abfd,
+ asymbol **alocation));
+extern void ecoff_get_symbol_info PARAMS ((bfd *abfd,
+ asymbol *symbol,
+ symbol_info *ret));
+extern void ecoff_print_symbol PARAMS ((bfd *abfd, PTR filep,
+ asymbol *symbol,
+ bfd_print_symbol_type how));
+extern unsigned int ecoff_canonicalize_reloc PARAMS ((bfd *abfd,
+ asection *section,
+ arelent **relptr,
+ asymbol **symbols));
+extern boolean ecoff_find_nearest_line PARAMS ((bfd *abfd,
+ asection *section,
+ asymbol **symbols,
+ bfd_vma offset,
+ CONST char **filename_ptr,
+ CONST char **fnname_ptr,
+ unsigned int *retline_ptr));
+extern boolean ecoff_bfd_seclet_link PARAMS ((bfd *abfd, PTR data,
+ boolean relocateable));
+extern boolean ecoff_set_arch_mach PARAMS ((bfd *abfd,
+ enum bfd_architecture arch,
+ unsigned long machine));
+extern int ecoff_sizeof_headers PARAMS ((bfd *abfd, boolean reloc));
+extern boolean ecoff_set_section_contents PARAMS ((bfd *abfd,
+ asection *section,
+ PTR location,
+ file_ptr offset,
+ bfd_size_type count));
+extern boolean ecoff_get_section_contents PARAMS ((bfd *abfd,
+ asection *section,
+ PTR location,
+ file_ptr offset,
+ bfd_size_type count));
+extern boolean ecoff_write_object_contents PARAMS ((bfd *abfd));
+extern boolean ecoff_slurp_armap PARAMS ((bfd *abfd));
+extern boolean ecoff_write_armap PARAMS ((bfd *abfd, unsigned int elength,
+ struct orl *map,
+ unsigned int orl_count,
+ int stridx));
+#define ecoff_slurp_extended_name_table _bfd_slurp_extended_name_table
+extern bfd_target *ecoff_archive_p PARAMS ((bfd *abfd));
+#define ecoff_get_lineno \
+ ((alent *(*) PARAMS ((bfd *, asymbol *))) bfd_nullvoidptr)
+#define ecoff_truncate_arname bfd_dont_truncate_arname
+#define ecoff_openr_next_archived_file bfd_generic_openr_next_archived_file
+#define ecoff_generic_stat_arch_elt bfd_generic_stat_arch_elt
+#define ecoff_get_reloc_upper_bound coff_get_reloc_upper_bound
+#define ecoff_close_and_cleanup bfd_generic_close_and_cleanup
+#define ecoff_bfd_debug_info_start bfd_void
+#define ecoff_bfd_debug_info_end bfd_void
+#define ecoff_bfd_debug_info_accumulate \
+ ((void (*) PARAMS ((bfd *, struct sec *))) bfd_void)
+#define ecoff_bfd_get_relocated_section_contents \
+ bfd_generic_get_relocated_section_contents
+#define ecoff_bfd_relax_section bfd_generic_relax_section
+#define ecoff_bfd_make_debug_symbol \
+ ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr)
+
+/* Hook functions for the generic COFF section reading code. */
+extern PTR ecoff_mkobject_hook PARAMS ((bfd *, PTR filehdr, PTR aouthdr));
+extern asection *ecoff_make_section_hook PARAMS ((bfd *abfd, char *name));
+extern boolean ecoff_new_section_hook PARAMS ((bfd *abfd,
+ asection *section));
+#define ecoff_set_alignment_hook \
+ ((void (*) PARAMS ((bfd *, asection *, PTR))) bfd_void)
+extern boolean ecoff_set_arch_mach_hook PARAMS ((bfd *abfd, PTR filehdr));
+extern long ecoff_sec_to_styp_flags PARAMS ((CONST char *name,
+ flagword flags));
+extern flagword ecoff_styp_to_sec_flags PARAMS ((bfd *abfd, PTR hdr));
+extern boolean 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..187c51a
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/libelf.h
@@ -0,0 +1,249 @@
+/* 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"
+
+/* 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)
+
+typedef struct
+{
+ asymbol symbol;
+ Elf_Internal_Sym internal_elf_sym;
+ union
+ {
+ unsigned int hppa_arg_reloc;
+ PTR any;
+ }
+ tc_data;
+} elf_symbol_type;
+
+struct elf_backend_data
+{
+ int use_rela_p;
+ int elf_64_p;
+ enum bfd_architecture arch;
+ void (*elf_info_to_howto) PARAMS ((bfd *, arelent *,
+ Elf_Internal_Rela *));
+ void (*elf_info_to_howto_rel) PARAMS ((bfd *, arelent *,
+ Elf_Internal_Rel *));
+ bfd_vma maxpagesize;
+ void (*write_relocs) PARAMS ((bfd *, asection *, PTR));
+
+ void (*elf_backend_symbol_processing) PARAMS ((bfd *, asymbol *));
+ boolean (*elf_backend_symbol_table_processing) PARAMS ((bfd *, elf_symbol_type *, int));
+ boolean (*elf_backend_section_processing) PARAMS ((bfd *, Elf32_Internal_Shdr *));
+ boolean (*elf_backend_section_from_shdr) PARAMS ((bfd *, Elf32_Internal_Shdr *, char *));
+ boolean (*elf_backend_fake_sections) PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *));
+ boolean (*elf_backend_section_from_bfd_section) PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *, int *));
+};
+
+struct elf_sym_extra
+{
+ int elf_sym_num; /* sym# after locals/globals are reordered */
+};
+
+typedef struct elf_sym_extra Elf_Sym_Extra;
+
+struct bfd_elf_arch_map {
+ enum bfd_architecture bfd_arch;
+ int elf_arch;
+};
+
+extern const struct bfd_elf_arch_map bfd_elf_arch_map[];
+extern const int bfd_elf_arch_map_size;
+
+struct bfd_elf_section_data {
+ Elf_Internal_Shdr this_hdr;
+ Elf_Internal_Shdr rel_hdr;
+ int this_idx, rel_idx;
+};
+#define elf_section_data(sec) ((struct bfd_elf_section_data*)sec->used_by_bfd)
+#define shdr_name(abfd,shdr) (elf_shstrtab (abfd)->tab + (shdr)->sh_name)
+
+#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_Internal_Sym *internal_syms;
+ elf_symbol_type *symbols; /* elf_symbol_type */
+ 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;
+ int symtab_section, shstrtab_section, strtab_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) */
+};
+
+#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_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 obj_symbols(bfd) (elf_tdata(bfd) -> symbols)
+#define obj_internal_syms(bfd) (elf_tdata(bfd) -> internal_syms)
+#define elf_gp(bfd) (elf_tdata(bfd) -> gp)
+#define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size)
+
+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 *));
+extern boolean bfd_elf_mkobject PARAMS ((bfd *));
+extern Elf_Internal_Shdr *bfd_elf_find_section PARAMS ((bfd *, char *));
+
+extern boolean bfd_elf32_write_object_contents PARAMS ((bfd *));
+extern boolean bfd_elf64_write_object_contents PARAMS ((bfd *));
+
+extern bfd_target *bfd_elf32_object_p PARAMS ((bfd *));
+extern 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 unsigned int bfd_elf32_get_symtab_upper_bound PARAMS ((bfd *));
+extern unsigned int bfd_elf32_get_symtab PARAMS ((bfd *, asymbol **));
+extern unsigned int bfd_elf32_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr));
+extern unsigned int 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 *));
+
+/* 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 bfd_target *bfd_elf64_object_p PARAMS ((bfd *));
+extern 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 unsigned int bfd_elf64_get_symtab_upper_bound PARAMS ((bfd *));
+extern unsigned int bfd_elf64_get_symtab PARAMS ((bfd *, asymbol **));
+extern unsigned int bfd_elf64_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr));
+extern unsigned int 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 *));
+
+/* 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/opncls.c b/gnu/usr.bin/gdb/bfd/opncls.c
new file mode 100644
index 0000000..42858c2
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/opncls.c
@@ -0,0 +1,534 @@
+/* opncls.c -- open and close a BFD.
+ Copyright (C) 1990-1991 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"
+extern void bfd_cache_init PARAMS ((bfd *));
+FILE *bfd_open_file PARAMS ((bfd *));
+
+/* fdopen is a loser -- we should use stdio exclusively. Unfortunately
+ if we do that we can't use fcntl. */
+
+
+#define obstack_chunk_alloc bfd_xmalloc_by_size_t
+#define obstack_chunk_free free
+
+/* Return a new BFD. All BFD's are allocated through this routine. */
+
+bfd *
+new_bfd PARAMS ((void))
+{
+ bfd *nbfd;
+
+ nbfd = (bfd *)zalloc (sizeof (bfd));
+ if (!nbfd)
+ return 0;
+
+ bfd_check_init();
+ obstack_begin((PTR)&nbfd->memory, 128);
+
+ 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 *
+new_bfd_contained_in (obfd)
+ bfd *obfd;
+{
+ bfd *nbfd;
+
+ nbfd = 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
+ This function opens the file supplied (using <<fopen>>) with the target
+ supplied, it returns a pointer to the created BFD.
+
+ If NULL is returned then an error has occured. Possible errors
+ are <<no_memory>>, <<invalid_target>> or <<system_call>> error.
+*/
+
+bfd *
+DEFUN(bfd_openr, (filename, target),
+ CONST char *filename AND
+ CONST char *target)
+{
+ bfd *nbfd;
+ bfd_target *target_vec;
+
+ nbfd = new_bfd();
+ if (nbfd == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+
+ target_vec = bfd_find_target (target, nbfd);
+ if (target_vec == NULL) {
+ bfd_error = invalid_target;
+ return NULL;
+ }
+
+ nbfd->filename = filename;
+ nbfd->direction = read_direction;
+
+ if (bfd_open_file (nbfd) == NULL) {
+ bfd_error = system_call_error; /* 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_closed, 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), set
+ bfd->cacheable nonzero in 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 no_memory, invalid_target and system_call
+ error.
+*/
+
+bfd *
+DEFUN(bfd_fdopenr,(filename, target, fd),
+ CONST char *filename AND
+ CONST char *target AND
+ int fd)
+{
+ bfd *nbfd;
+ bfd_target *target_vec;
+ int fdflags;
+
+ bfd_error = system_call_error;
+
+#ifdef NO_FCNTL
+ fdflags = O_RDWR; /* Assume full access */
+#else
+ fdflags = fcntl (fd, F_GETFL, NULL);
+#endif
+ if (fdflags == -1) return NULL;
+
+ nbfd = new_bfd();
+
+ if (nbfd == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+
+ target_vec = bfd_find_target (target, nbfd);
+ if (target_vec == NULL) {
+ 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 ();
+ }
+
+ bfd_cache_init (nbfd);
+
+ 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
+ Creates a BFD, associated with file @var{filename}, using the
+ file format @var{target}, and returns a pointer to it.
+
+ Possible errors are system_call_error, no_memory,
+ invalid_target.
+*/
+
+bfd *
+DEFUN(bfd_openw,(filename, target),
+ CONST char *filename AND
+ CONST char *target)
+{
+ bfd *nbfd;
+ bfd_target *target_vec;
+
+ bfd_error = system_call_error;
+
+ /* nbfd has to point to head of malloc'ed block so that bfd_close may
+ reclaim it correctly. */
+
+ nbfd = new_bfd();
+ if (nbfd == NULL) {
+ 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_error = system_call_error; /* File not writeable, etc */
+ (void) obstack_free (&nbfd->memory, (PTR)0);
+ return NULL;
+ }
+ return nbfd;
+}
+
+/*
+
+FUNCTION
+ bfd_close
+
+SYNOPSIS
+ boolean bfd_close(bfd *);
+
+DESCRIPTION
+
+ This function closes 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
+DEFUN(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
+ This function closes a BFD. It 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
+DEFUN(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 the
+ supplied BFD.
+
+*/
+
+bfd_size_type
+DEFUN(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
+ This routine creates 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 *
+DEFUN(bfd_create,(filename, templ),
+ CONST char *filename AND
+ bfd *templ)
+{
+ bfd *nbfd = new_bfd();
+ if (nbfd == (bfd *)NULL) {
+ 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
+ This function allocates a block of memory in the obstack
+ attatched to <<abfd>> and returns a pointer to it.
+*/
+
+
+PTR
+DEFUN(bfd_alloc_by_size_t,(abfd, size),
+ bfd *abfd AND
+ size_t size)
+{
+ PTR res = obstack_alloc(&(abfd->memory), size);
+ return res;
+}
+
+DEFUN(void bfd_alloc_grow,(abfd, ptr, size),
+ bfd *abfd AND
+ PTR ptr AND
+ size_t size)
+{
+ (void) obstack_grow(&(abfd->memory), ptr, size);
+}
+DEFUN(PTR bfd_alloc_finish,(abfd),
+ bfd *abfd)
+{
+ return obstack_finish(&(abfd->memory));
+}
+
+DEFUN(PTR bfd_alloc, (abfd, size),
+ bfd *abfd AND
+ size_t size)
+{
+ return bfd_alloc_by_size_t(abfd, (size_t)size);
+}
+
+DEFUN(PTR bfd_zalloc,(abfd, size),
+ bfd *abfd AND
+ size_t size)
+{
+ PTR res;
+ res = bfd_alloc(abfd, size);
+ memset(res, 0, (size_t)size);
+ return res;
+}
+
+DEFUN(PTR bfd_realloc,(abfd, old, size),
+ bfd *abfd AND
+ PTR old AND
+ size_t size)
+{
+ PTR res = bfd_alloc(abfd, size);
+ 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..f2dd520
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/reloc.c
@@ -0,0 +1,1225 @@
+/* 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 was as it maintains
+ symbols; they are left alone until required, then read in
+ en-mass and traslated into an internal form. There is a common
+ routine <<bfd_perform_relocation>> which acts upon the
+ canonical form to do the actual fixup.
+
+ Note that relocations are maintained on a per section basis,
+ whilst symbols are maintained on a per BFD basis.
+
+ All a back end has to do to fit the BFD interface is to create
+ as many <<struct reloc_cache_entry>> as there are relocations
+ in a particular section, and fill in the right bits:
+
+@menu
+@* typedef arelent::
+@* howto manager::
+@end menu
+
+*/
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "seclet.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,
+.
+. {* Unused *}
+. bfd_reloc_notsupported,
+.
+. {* Unsupported relocation size requested. *}
+. 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. *}
+. 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 a relent:
+
+ o sym_ptr_ptr
+
+ The symbol table pointer points to a pointer to the symbol
+ associated with the relocation request. This would naturally
+ be 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 odd sized lumps. The designers of
+ the a.out format chose not to use the data within the section
+ for storing part of the offset; all the offset is kept within
+ the reloc. Any thing 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 contains a pointer to foo, and the offsets would
+ 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 struct which
+ contains information on what to do with all 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 BFD needs to know to tie up a back end's data.
+
+CODE_FRAGMENT
+.struct symbol_cache_entry; {* Forward declaration *}
+.
+.typedef CONST struct reloc_howto_struct
+.{
+. {* The type field has mainly a documetary use - the back end can
+. to what it wants with it, though the normally the back end's
+. external idea of what a reloc number would be would be stored
+. in this field. For example, the a PC relative word relocation
+. in a coff environment would have 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.
+. 0 : one byte
+. 1 : two bytes
+. 2 : four bytes
+. 3 : nothing done (unless special_function is nonzero)
+. 4 : eight bytes
+. -2 : two bytes, result should be subtracted from the
+. data instead of added
+. There is currently no trivial way to extract a "number of
+. bytes" from a howto pointer. *}
+. 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));
+.
+. {* 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 is used to select what 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 is what 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;
+.
+.} reloc_howto_type;
+
+*/
+
+/*
+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; \
+. } \
+. } \
+.}
+
+*/
+
+/*
+TYPEDEF
+ reloc_chain
+
+DESCRIPTION
+
+ How relocs are tied together
+
+.typedef unsigned char bfd_byte;
+.
+.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);
+
+DESCRIPTION
+ If an 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.
+
+*/
+
+
+bfd_reloc_status_type
+DEFUN(bfd_perform_relocation,(abfd,
+ reloc_entry,
+ data,
+ input_section,
+ output_bfd),
+ bfd *abfd AND
+ arelent *reloc_entry AND
+ PTR data AND
+ asection *input_section AND
+ bfd *output_bfd)
+{
+ bfd_vma relocation;
+ bfd_reloc_status_type flag = bfd_reloc_ok;
+ bfd_size_type addr = reloc_entry->address ;
+ bfd_vma output_base = 0;
+ reloc_howto_type *howto = reloc_entry->howto;
+ asection *reloc_target_output_section ;
+
+ asymbol *symbol;
+
+ symbol = *( reloc_entry->sym_ptr_ptr);
+ if ((symbol->section == &bfd_abs_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 (symbol->section == &bfd_und_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);
+ 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)
+ {
+ relocation -= reloc_entry->addend;
+ 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)
+ */
+ relocation >>= howto->rightshift;
+
+ /* Shift everything up to where it's going to be used */
+
+ relocation <<= 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;
+}
+
+
+
+/*
+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_16,
+. 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,
+.
+. {* 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,
+.
+. {* 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,
+.
+.
+. {* Bits 27..2 of the relocation address shifted right 2 bits;
+. simple reloc otherwise. *}
+. BFD_RELOC_MIPS_JMP,
+.
+. {* signed 16-bit pc-relative, shifted right 2 bits (e.g. for MIPS) *}
+. BFD_RELOC_16_PCREL_S2,
+.
+. {* 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,
+.
+. {* 16 bit relocation relative to the global pointer. *}
+. BFD_RELOC_MIPS_GPREL,
+.
+. {* These are, so far, specific to HPPA processors. I'm not sure that some
+. don't duplicate other reloc types, such as BFD_RELOC_32 and _32_PCREL.
+. Also, many more were in the list I got that don't fit in well in the
+. model BFD uses, so I've omitted them for now. If we do make this reloc
+. type get used for code that really does implement the funky reloc types,
+. they'll have to be added to this list. *}
+. BFD_RELOC_HPPA_32,
+. BFD_RELOC_HPPA_11,
+. BFD_RELOC_HPPA_14,
+. BFD_RELOC_HPPA_17,
+.
+. BFD_RELOC_HPPA_L21,
+. BFD_RELOC_HPPA_R11,
+. BFD_RELOC_HPPA_R14,
+. BFD_RELOC_HPPA_R17,
+. BFD_RELOC_HPPA_LS21,
+. BFD_RELOC_HPPA_RS11,
+. BFD_RELOC_HPPA_RS14,
+. BFD_RELOC_HPPA_RS17,
+. BFD_RELOC_HPPA_LD21,
+. BFD_RELOC_HPPA_RD11,
+. BFD_RELOC_HPPA_RD14,
+. BFD_RELOC_HPPA_RD17,
+. BFD_RELOC_HPPA_LR21,
+. BFD_RELOC_HPPA_RR14,
+. BFD_RELOC_HPPA_RR17,
+.
+. BFD_RELOC_HPPA_GOTOFF_11,
+. BFD_RELOC_HPPA_GOTOFF_14,
+. BFD_RELOC_HPPA_GOTOFF_L21,
+. BFD_RELOC_HPPA_GOTOFF_R11,
+. BFD_RELOC_HPPA_GOTOFF_R14,
+. BFD_RELOC_HPPA_GOTOFF_LS21,
+. BFD_RELOC_HPPA_GOTOFF_RS11,
+. BFD_RELOC_HPPA_GOTOFF_RS14,
+. BFD_RELOC_HPPA_GOTOFF_LD21,
+. BFD_RELOC_HPPA_GOTOFF_RD11,
+. BFD_RELOC_HPPA_GOTOFF_RD14,
+. BFD_RELOC_HPPA_GOTOFF_LR21,
+. BFD_RELOC_HPPA_GOTOFF_RR14,
+.
+. BFD_RELOC_HPPA_DLT_32,
+. BFD_RELOC_HPPA_DLT_11,
+. BFD_RELOC_HPPA_DLT_14,
+. BFD_RELOC_HPPA_DLT_L21,
+. BFD_RELOC_HPPA_DLT_R11,
+. BFD_RELOC_HPPA_DLT_R14,
+.
+. BFD_RELOC_HPPA_ABS_CALL_11,
+. BFD_RELOC_HPPA_ABS_CALL_14,
+. BFD_RELOC_HPPA_ABS_CALL_17,
+. BFD_RELOC_HPPA_ABS_CALL_L21,
+. BFD_RELOC_HPPA_ABS_CALL_R11,
+. BFD_RELOC_HPPA_ABS_CALL_R14,
+. BFD_RELOC_HPPA_ABS_CALL_R17,
+. BFD_RELOC_HPPA_ABS_CALL_LS21,
+. BFD_RELOC_HPPA_ABS_CALL_RS11,
+. BFD_RELOC_HPPA_ABS_CALL_RS14,
+. BFD_RELOC_HPPA_ABS_CALL_RS17,
+. BFD_RELOC_HPPA_ABS_CALL_LD21,
+. BFD_RELOC_HPPA_ABS_CALL_RD11,
+. BFD_RELOC_HPPA_ABS_CALL_RD14,
+. BFD_RELOC_HPPA_ABS_CALL_RD17,
+. BFD_RELOC_HPPA_ABS_CALL_LR21,
+. BFD_RELOC_HPPA_ABS_CALL_RR14,
+. BFD_RELOC_HPPA_ABS_CALL_RR17,
+.
+. BFD_RELOC_HPPA_PCREL_CALL_11,
+. BFD_RELOC_HPPA_PCREL_CALL_12,
+. BFD_RELOC_HPPA_PCREL_CALL_14,
+. BFD_RELOC_HPPA_PCREL_CALL_17,
+. BFD_RELOC_HPPA_PCREL_CALL_L21,
+. BFD_RELOC_HPPA_PCREL_CALL_R11,
+. BFD_RELOC_HPPA_PCREL_CALL_R14,
+. BFD_RELOC_HPPA_PCREL_CALL_R17,
+. BFD_RELOC_HPPA_PCREL_CALL_LS21,
+. BFD_RELOC_HPPA_PCREL_CALL_RS11,
+. BFD_RELOC_HPPA_PCREL_CALL_RS14,
+. BFD_RELOC_HPPA_PCREL_CALL_RS17,
+. BFD_RELOC_HPPA_PCREL_CALL_LD21,
+. BFD_RELOC_HPPA_PCREL_CALL_RD11,
+. BFD_RELOC_HPPA_PCREL_CALL_RD14,
+. BFD_RELOC_HPPA_PCREL_CALL_RD17,
+. BFD_RELOC_HPPA_PCREL_CALL_LR21,
+. BFD_RELOC_HPPA_PCREL_CALL_RR14,
+. BFD_RELOC_HPPA_PCREL_CALL_RR17,
+.
+. BFD_RELOC_HPPA_PLABEL_32,
+. BFD_RELOC_HPPA_PLABEL_11,
+. BFD_RELOC_HPPA_PLABEL_14,
+. BFD_RELOC_HPPA_PLABEL_L21,
+. BFD_RELOC_HPPA_PLABEL_R11,
+. BFD_RELOC_HPPA_PLABEL_R14,
+.
+. BFD_RELOC_HPPA_UNWIND_ENTRY,
+. BFD_RELOC_HPPA_UNWIND_ENTRIES,
+.
+. {* 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,
+.
+. {* this must be the highest numeric value *}
+. BFD_RELOC_UNUSED
+. } bfd_reloc_code_real_type;
+*/
+
+
+/*
+SECTION
+ bfd_reloc_type_lookup
+
+SYNOPSIS
+ CONST struct reloc_howto_struct *
+ bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code);
+
+DESCRIPTION
+ This routine returns a pointer to a howto struct which when
+ invoked, will perform the supplied relocation on data from the
+ architecture noted.
+
+*/
+
+
+CONST struct reloc_howto_struct *
+DEFUN(bfd_reloc_type_lookup,(abfd, code),
+ bfd *abfd AND
+ 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 AND
+ bfd_reloc_code_real_type code);
+
+DESCRIPTION
+ Provides a default relocation lookup routine for any architecture.
+
+
+*/
+
+CONST struct reloc_howto_struct *
+DEFUN(bfd_default_reloc_type_lookup, (abfd, code),
+ bfd *abfd AND
+ 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,
+ asymbol **symbols);
+
+DESCRIPTION
+ Provides default handling for relaxing for back ends which
+ don't do relaxing -- i.e., does nothing.
+*/
+
+boolean
+DEFUN(bfd_generic_relax_section,(abfd, section, symbols),
+ bfd *abfd AND
+ asection *section AND
+ asymbol **symbols)
+{
+
+ return false;
+
+}
+
+
+/*
+INTERNAL_FUNCTION
+ bfd_generic_get_relocated_section_contents
+
+SYNOPSIS
+ bfd_byte *
+ bfd_generic_get_relocated_section_contents (bfd *abfd,
+ struct bfd_seclet *seclet,
+ bfd_byte *data,
+ boolean relocateable);
+
+DESCRIPTION
+ Provides default handling of relocation effort for back ends
+ which can't be bothered to do it efficiently.
+
+*/
+
+bfd_byte *
+DEFUN(bfd_generic_get_relocated_section_contents,(abfd,
+ seclet,
+ data,
+ relocateable),
+ bfd *abfd AND
+ struct bfd_seclet *seclet AND
+ bfd_byte *data AND
+ boolean relocateable)
+{
+ extern bfd_error_vector_type bfd_error_vector;
+
+ /* Get enough memory to hold the stuff */
+ bfd *input_bfd = seclet->u.indirect.section->owner;
+ asection *input_section = seclet->u.indirect.section;
+
+
+
+ size_t reloc_size = bfd_get_reloc_upper_bound(input_bfd, input_section);
+ arelent **reloc_vector = (arelent **) alloca(reloc_size);
+
+ /* read in the section */
+ bfd_get_section_contents(input_bfd,
+ input_section,
+ data,
+ 0,
+ input_section->_raw_size);
+
+/* 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;
+
+
+ if (bfd_canonicalize_reloc(input_bfd,
+ input_section,
+ reloc_vector,
+ seclet->u.indirect.symbols) )
+ {
+ arelent **parent;
+ for (parent = reloc_vector; * parent != (arelent *)NULL;
+ parent++)
+ {
+ bfd_reloc_status_type r=
+ bfd_perform_relocation(input_bfd,
+ *parent,
+ data,
+ input_section,
+ relocateable ? abfd : (bfd *) NULL);
+
+ 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:
+ bfd_error_vector.undefined_symbol(*parent, seclet);
+ break;
+ case bfd_reloc_dangerous:
+ bfd_error_vector.reloc_dangerous(*parent, seclet);
+ break;
+ case bfd_reloc_outofrange:
+ case bfd_reloc_overflow:
+ bfd_error_vector.reloc_value_truncated(*parent, seclet);
+ break;
+ default:
+ abort();
+ break;
+ }
+
+ }
+ }
+ }
+
+
+ return data;
+
+
+}
diff --git a/gnu/usr.bin/gdb/bfd/seclet.c b/gnu/usr.bin/gdb/bfd/seclet.c
new file mode 100644
index 0000000..5dcc59a
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/seclet.c
@@ -0,0 +1,185 @@
+/* seclet.c
+ 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. */
+
+/* This module is part of BFD */
+
+
+/* The intention is that one day, all the code which uses sections
+ will change and use seclets instead - maybe seglet would have been
+ a better name..
+
+ Anyway, a seclet contains enough info to be able to describe an
+ area of output memory in one go.
+
+ The only description so far catered for is that of the
+ <<bfd_indirect_seclet>>, which is a select which points to a
+ <<section>> and the <<asymbols>> associated with the section, so
+ that relocation can be done when needed.
+
+ One day there will be more types - they will at least migrate from
+ the linker's data structures - also there could be extra stuff,
+ like a bss seclet, which descibes a lump of memory as containing
+ zeros compactly, without the horrible SEC_* flag cruft.
+
+
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "seclet.h"
+#include "coff/internal.h"
+
+/* Create a new seclet and attach it to a section. */
+
+bfd_seclet_type *
+DEFUN(bfd_new_seclet,(abfd, section),
+ bfd *abfd AND
+ asection *section)
+{
+ bfd_seclet_type *n = (bfd_seclet_type *)bfd_alloc(abfd, sizeof(bfd_seclet_type));
+ if (section->seclets_tail != (bfd_seclet_type *)NULL) {
+ section->seclets_tail->next = n;
+ }
+ else
+ {
+ section->seclets_head = n;
+ }
+ section->seclets_tail = n;
+
+ return n;
+}
+
+/* Given an indirect seclet which points to an input section, relocate
+ the contents of the seclet and put the data in its final
+ destination. */
+
+static boolean
+DEFUN(rel,(abfd, seclet, output_section, data, relocateable),
+ bfd *abfd AND
+ bfd_seclet_type *seclet AND
+ asection *output_section AND
+ PTR data AND
+ boolean relocateable)
+{
+ if ((output_section->flags & SEC_HAS_CONTENTS) != 0
+ && seclet->size)
+ {
+ data = (PTR) bfd_get_relocated_section_contents(abfd, seclet, data,
+ relocateable);
+ if(bfd_set_section_contents(abfd,
+ output_section,
+ data,
+ seclet->offset,
+ seclet->size) == false)
+ {
+ abort();
+ }
+ }
+ return true;
+}
+
+/* Put the contents of a seclet in its final destination. */
+
+static boolean
+DEFUN(seclet_dump_seclet,(abfd, seclet, section, data, relocateable),
+ bfd *abfd AND
+ bfd_seclet_type *seclet AND
+ asection *section AND
+ PTR data AND
+ boolean relocateable)
+{
+ switch (seclet->type)
+ {
+ case bfd_indirect_seclet:
+ /* The contents of this section come from another one somewhere
+ else */
+ return rel(abfd, seclet, section, data, relocateable);
+
+ case bfd_fill_seclet:
+ /* Fill in the section with us */
+ {
+ char *d = bfd_xmalloc(seclet->size);
+ unsigned int i;
+ for (i =0; i < seclet->size; i+=2) {
+ d[i] = seclet->u.fill.value >> 8;
+ }
+ for (i = 1; i < seclet->size; i+=2) {
+ d[i] = seclet->u.fill.value ;
+ }
+ /* Don't bother to fill in empty sections */
+ if (!(bfd_get_section_flags(abfd, section) & SEC_HAS_CONTENTS))
+ {
+ return true;
+ }
+ return bfd_set_section_contents(abfd, section, d, seclet->offset,
+ seclet->size);
+ }
+
+ default:
+ abort();
+ }
+
+ return true;
+}
+
+/*
+INTERNAL_FUNCTION
+ bfd_generic_seclet_link
+
+SYNOPSIS
+ boolean bfd_generic_seclet_link
+ (bfd *abfd,
+ PTR data,
+ boolean relocateable);
+
+DESCRIPTION
+
+ The generic seclet linking routine. The caller should have
+ set up seclets for all the output sections. The DATA argument
+ should point to a memory area large enough to hold the largest
+ section. This function looks through the seclets and moves
+ the contents into the output sections. If RELOCATEABLE is
+ true, the orelocation fields of the output sections must
+ already be initialized.
+
+*/
+
+boolean
+DEFUN(bfd_generic_seclet_link,(abfd, data, relocateable),
+ bfd *abfd AND
+ PTR data AND
+ boolean relocateable)
+{
+ asection *o = abfd->sections;
+ while (o != (asection *)NULL)
+ {
+ bfd_seclet_type *p = o->seclets_head;
+ while (p != (bfd_seclet_type *)NULL)
+ {
+ if (seclet_dump_seclet(abfd, p, o, data, relocateable) == false)
+ return false;
+ p = p ->next;
+ }
+ o = o->next;
+ }
+
+ return true;
+}
diff --git a/gnu/usr.bin/gdb/bfd/seclet.h b/gnu/usr.bin/gdb/bfd/seclet.h
new file mode 100644
index 0000000..de5fdff
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/seclet.h
@@ -0,0 +1,55 @@
+/* Definitions of little sections (seclets) for BFD.
+ Copyright 1992 Free Software Foundation, Inc.
+ Hacked 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. */
+
+#ifndef _SECLET_H
+#define _SECLET_H
+
+enum bfd_seclet_enum
+{
+ bfd_indirect_seclet,
+ bfd_fill_seclet
+};
+
+struct bfd_seclet
+{
+ struct bfd_seclet *next;
+ enum bfd_seclet_enum type;
+ unsigned int offset;
+ unsigned int size;
+ union
+ {
+ struct
+ {
+ asection *section;
+ asymbol **symbols;
+ } indirect;
+ struct {
+ int value;
+ } fill;
+ }
+ u;
+};
+
+typedef struct bfd_seclet bfd_seclet_type;
+
+bfd_seclet_type *
+bfd_new_seclet PARAMS ((bfd *, asection *));
+
+#endif
diff --git a/gnu/usr.bin/gdb/bfd/section.c b/gnu/usr.bin/gdb/bfd/section.c
new file mode 100644
index 0000000..547c69e
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/section.c
@@ -0,0 +1,899 @@
+/* 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
+
+ Sections are supported in BFD in <<section.c>>.
+
+ The raw data contained within a BFD is maintained through the
+ section abstraction. A single BFD may have any number of
+ sections, and keeps hold of them by pointing to the first,
+ each one points to the next in the list.
+
+@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 a supernumary section
+ <<COMMON>> for each input file's BFD to hold information about
+ common storage.
+
+ The raw data is not necessarily read in at the same time as
+ 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 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 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 (ie at vma
+ 0x100) and "B" at offset 0x20 (ie at vma 0x120) the 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
+ Seglets
+
+ The data within a section is stored in a <<seglet>>. These
+ are much like the fixups in <<gas>>. The seglet abstraction
+ allows the a section to grow and shrink within itself.
+
+ A seglet knows how big it is, and which is the next seglet and
+ where the raw data for it is, and also points to a list of
+ relocations which apply to it.
+
+ The seglet is used by the linker to perform relaxing on final
+ code. The application 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 seglet by seglet basis.
+
+*/
+
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+
+/*
+DOCDD
+INODE
+typedef asection, section prototypes, Section Output, Sections
+SUBSECTION
+ typedef asection
+
+ The shape of a section struct:
+
+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 of
+. 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 loaded.
+. This would 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 would be clear for a .bss section *}
+.#define SEC_LOAD 0x002
+.
+. {* The section contains data still to be relocated, so there will
+. be 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 (eg <<__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 relocte 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 not to output sections
+. containing this flag even if they have information which
+. would normally be written. *}
+.#define SEC_NEVER_LOAD 0x400
+.
+. {* The section is a shared library section. The linker must leave
+. these completely alone, as the vma and size are used when
+. the executable is loaded. *}
+.#define SEC_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), 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
+.
+. {* 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 (eg, the
+. size of <<.bss>>). This will be filled in after relocation *}
+.
+. bfd_size_type _cooked_size;
+.
+. {* The size on disk of the section in bytes originally. 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. Eg, 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 - eg
+. 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;
+.
+. struct lang_output_section *otheruserdata;
+.
+. {* 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_seclet *seclets_head;
+. struct bfd_seclet *seclets_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. *}
+.#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 asection bfd_abs_section;
+. {* Pointer to the undefined section *}
+.extern asection bfd_und_section;
+. {* Pointer to the common section *}
+.extern asection bfd_com_section;
+. {* Pointer to the indirect section *}
+.extern asection bfd_ind_section;
+.
+.extern struct symbol_cache_entry *bfd_abs_symbol;
+.extern struct symbol_cache_entry *bfd_com_symbol;
+.extern struct symbol_cache_entry *bfd_und_symbol;
+.extern struct symbol_cache_entry *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, &bfd_com_section },
+ { 0, BFD_UND_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_und_section },
+ { 0, BFD_ABS_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_abs_section },
+ { 0, BFD_IND_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_ind_section },
+};
+
+#define STD_SECTION(SEC, FLAGS, SYM, NAME, IDX) \
+ asymbol *SYM = (asymbol *) &global_syms[IDX]; \
+ asection SEC = { NAME, 0, 0, FLAGS, 0, 0, (boolean) 0, 0, 0, 0, &SEC,\
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (boolean) 0, \
+ (asymbol *) &global_syms[IDX], &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
+<<libbfd>.
+*/
+
+/*
+FUNCTION
+ bfd_get_section_by_name
+
+SYNOPSIS
+ asection *bfd_get_section_by_name(bfd *abfd, CONST char *name);
+
+DESCRIPTION
+ Runs through the provided @var{abfd} and returns the one of the
+ <<asection>>s who's name matches that provided, 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 *
+DEFUN(bfd_get_section_by_name,(abfd, name),
+ bfd *abfd AND
+ 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 *, CONST char *name);
+
+DESCRIPTION
+ This function creates a new empty section called @var{name}
+ and attaches it to the end of the chain of sections for the
+ BFD supplied. 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 is was rewritten...
+
+ Possible errors are:
+ o invalid_operation -
+ If output has already started for this BFD.
+ o no_memory -
+ If obstack alloc fails.
+
+*/
+
+
+asection *
+DEFUN(bfd_make_section_old_way,(abfd, name),
+ bfd *abfd AND
+ 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 *, 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.
+
+ Returns NULL and sets bfd_error on error; possible errors are:
+ o invalid_operation - If output has already started for @var{abfd}.
+ o 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_error = invalid_operation;
+ return NULL;
+ }
+
+ while (sect) {
+ prev = &sect->next;
+ sect = sect->next;
+ }
+
+ newsect = (asection *) bfd_zalloc(abfd, sizeof (asection));
+ if (newsect == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+
+ newsect->name = name;
+ newsect->index = abfd->section_count++;
+ newsect->flags = SEC_NO_FLAGS;
+
+ newsect->userdata = 0;
+ 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);
+ 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 setting
+ bfd_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.
+*/
+
+sec_ptr
+DEFUN(bfd_make_section,(abfd, name),
+ bfd *abfd AND
+ CONST char * name)
+{
+ asection * sect = abfd->sections;
+
+ if (strcmp(name, BFD_ABS_SECTION_NAME) == 0)
+ {
+ return &bfd_abs_section;
+ }
+ if (strcmp(name, BFD_COM_SECTION_NAME) == 0)
+ {
+ return &bfd_com_section;
+ }
+ if (strcmp(name, BFD_UND_SECTION_NAME) == 0)
+ {
+ return &bfd_und_section;
+ }
+
+ if (strcmp(name, BFD_IND_SECTION_NAME) == 0)
+ {
+ return &bfd_ind_section;
+ }
+
+ 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 *, asection *, flagword);
+
+DESCRIPTION
+ Attempts to set the attributes of the section named in the BFD
+ supplied to the value. Returns true on success, false on
+ error. Possible error returns are:
+
+ o 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.
+
+*/
+
+boolean
+DEFUN(bfd_set_section_flags,(abfd, section, flags),
+ bfd *abfd AND
+ sec_ptr section AND
+ 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_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
+ Calls 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
+DEFUN(bfd_map_over_sections,(abfd, operation, user_storage),
+ bfd *abfd AND
+ void (*operation) PARAMS ((bfd *abfd, asection *sect, PTR obj)) AND
+ 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 *, asection *, bfd_size_type val);
+
+DESCRIPTION
+ Sets @var{section} to the size @var{val}. If the operation is
+ ok, then <<true>> is returned, else <<false>>.
+
+ Possible error returns:
+ o invalid_operation -
+ Writing has started to the BFD, so setting the size is invalid
+
+*/
+
+boolean
+DEFUN(bfd_set_section_size,(abfd, ptr, val),
+ bfd *abfd AND
+ sec_ptr ptr AND
+ 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_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 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
+DEFUN(bfd_set_section_contents,(abfd, section, location, offset, count),
+ bfd *abfd AND
+ sec_ptr section AND
+ PTR location AND
+ file_ptr offset AND
+ bfd_size_type count)
+{
+ bfd_size_type sz;
+
+ if (!bfd_get_section_flags(abfd, section) & SEC_HAS_CONTENTS)
+ {
+ bfd_error = no_contents;
+ return(false);
+ }
+
+ if (offset < 0)
+ {
+ bad_val:
+ 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_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
+ This function reads 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 constuctor with the <<SEC_CONSTUCTOR>>
+ flag set are requested, then the @var{location} is filled with
+ zeroes. If no errors occur, <<true>> is returned, else
+ <<false>>.
+
+
+
+*/
+boolean
+DEFUN(bfd_get_section_contents,(abfd, section, location, offset, count),
+ bfd *abfd AND
+ sec_ptr section AND
+ PTR location AND
+ file_ptr offset AND
+ 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_error = bad_value;
+ return false;
+ }
+ sz = bfd_get_section_size_now (abfd, section);
+ if (offset > sz
+ || count > sz
+ || offset + count > sz)
+ goto bad_val;
+
+ if (count == 0)
+ /* Don't bother. */
+ return true;
+
+ return BFD_SEND (abfd, _bfd_get_section_contents,
+ (abfd, section, location, offset, count));
+}
diff --git a/gnu/usr.bin/gdb/bfd/srec.c b/gnu/usr.bin/gdb/bfd/srec.c
new file mode 100644
index 0000000..88ba957
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/srec.c
@@ -0,0 +1,1001 @@
+/* BFD back-end for s-record objects.
+ Copyright 1990, 1991, 1992, 1993 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"
+
+/* Macros for converting between hex and binary */
+
+static CONST char digs[] = "0123456789ABCDEF";
+
+static char hex_value[1 + (unsigned char)~0];
+
+#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)
+
+
+
+static void
+DEFUN_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;
+
+
+/*
+ called once per input S-Record, used to work out vma and size of data.
+ */
+
+static bfd_vma low,high;
+
+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);
+ 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;
+ p->udata = 0;
+ }
+}
+static void
+DEFUN(size_srec,(abfd, section, address, raw, length),
+ bfd *abfd AND
+ asection *section AND
+ bfd_vma address AND
+ bfd_byte *raw AND
+ 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
+ */
+
+static void
+DEFUN(fillup,(abfd, section, address, raw, length),
+bfd *abfd AND
+asection *section AND
+bfd_vma address AND
+bfd_byte *raw AND
+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
+DEFUN(srec_mkobject, (abfd),
+ bfd *abfd)
+{
+ if (abfd->tdata.srec_data == 0)
+ {
+ tdata_type *tdata = (tdata_type *)bfd_alloc(abfd, sizeof(tdata_type));
+ abfd->tdata.srec_data = tdata;
+ tdata->type = 1;
+ tdata->head = (srec_data_list_type *)NULL;
+ }
+ return true;
+
+}
+
+static void
+DEFUN(pass_over,(abfd, func, symbolfunc, section),
+ bfd *abfd AND
+ void (*func)() AND
+ void (*symbolfunc)() AND
+ asection *section)
+{
+ unsigned int bytes_on_line;
+ boolean eof = false;
+
+ srec_mkobject(abfd);
+ /* To the front of the file */
+ bfd_seek(abfd, (file_ptr)0, SEEK_SET);
+ 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:
+ eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1);
+ 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' && 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 */
+ bfd_read(src, 1, 3, abfd);
+
+ type = *src++;
+
+ if (!ISHEX (src[0]) || !ISHEX (src[1]))
+ break;
+
+ bytes_on_line = HEX(src);
+
+ if (bytes_on_line > MAXCHUNK/2)
+ break;
+ src+=2 ;
+
+ bfd_read(src, 1 , bytes_on_line * 2, abfd);
+
+ 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 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 bfd_target *
+DEFUN(srec_object_p, (abfd),
+ bfd *abfd)
+{
+ char b[4];
+
+ srec_init();
+
+ bfd_seek(abfd, (file_ptr)0, SEEK_SET);
+ bfd_read(b, 1, 4, abfd);
+
+ if (b[0] != 'S' || !ISHEX(b[1]) || !ISHEX(b[2]) || !ISHEX(b[3]))
+ return (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 bfd_target *
+DEFUN(symbolsrec_object_p, (abfd),
+ bfd *abfd)
+{
+ char b[4];
+
+ srec_init();
+
+ bfd_seek(abfd, (file_ptr)0, SEEK_SET);
+ bfd_read(b, 1, 4, abfd);
+
+ if (b[0] != '$' || b[1] != '$')
+ return (bfd_target*) NULL;
+
+ return object_p(abfd);
+}
+
+
+static boolean
+DEFUN(srec_get_section_contents,(abfd, section, location, offset, count),
+ bfd *abfd AND
+ asection *section AND
+ PTR location AND
+ file_ptr offset AND
+ bfd_size_type count)
+{
+ if (section->used_by_bfd == (PTR)NULL)
+ {
+ section->used_by_bfd = (PTR)bfd_alloc (abfd, section->_raw_size);
+
+ pass_over(abfd, fillup, fillup_symbols, section);
+ }
+ (void) memcpy((PTR)location,
+ (PTR)((char *)(section->used_by_bfd) + offset),
+ count);
+ return true;
+}
+
+
+
+boolean
+DEFUN(srec_set_arch_mach,(abfd, arch, machine),
+ bfd *abfd AND
+ enum bfd_architecture arch AND
+ 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
+DEFUN(srec_set_section_contents,(abfd, section, location, offset, bytes_to_do),
+ bfd *abfd AND
+ sec_ptr section AND
+ PTR location AND
+ file_ptr offset AND
+ 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 ((section->flags & SEC_ALLOC)
+ && (section->flags & SEC_LOAD))
+ {
+ unsigned char *data = (unsigned char *) bfd_alloc(abfd, bytes_to_do);
+ memcpy(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
+void DEFUN(srec_write_record,(abfd, type, address, data, end),
+ bfd *abfd AND
+ char type AND
+ bfd_vma address AND
+ CONST unsigned char *data AND
+ CONST unsigned char *end)
+
+{
+ char buffer[MAXCHUNK];
+
+ unsigned int check_sum = 0;
+ unsigned CONST 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';
+ bfd_write((PTR)buffer, 1, dst - buffer , abfd);
+}
+
+
+
+static void
+DEFUN(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];
+ }
+ srec_write_record(abfd,0, 0, buffer, dst);
+}
+
+static void
+DEFUN(srec_write_section,(abfd, tdata, list),
+ bfd *abfd AND
+ tdata_type *tdata AND
+ 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;
+
+ srec_write_record(abfd,
+ tdata->type,
+ address,
+ location,
+ location + bytes_this_chunk);
+
+ bytes_written += bytes_this_chunk;
+ location += bytes_this_chunk;
+ }
+
+}
+
+static void
+DEFUN(srec_write_terminator,(abfd, tdata),
+ bfd *abfd AND
+ tdata_type *tdata)
+{
+ unsigned char buffer[2];
+
+ srec_write_record(abfd, 10 - tdata->type,
+ abfd->start_address, buffer, buffer);
+}
+
+
+
+static void
+srec_write_symbols(abfd)
+ bfd *abfd;
+{
+ char buffer[MAXCHUNK];
+ /* Dump out the symbols of a bfd */
+ int i;
+ int len = bfd_get_symcount(abfd);
+
+ if (len)
+ {
+ asymbol **table = bfd_get_outsymbols(abfd);
+ sprintf(buffer, "$$ %s\r\n", abfd->filename);
+
+ bfd_write(buffer, strlen(buffer), 1, abfd);
+
+ for (i = 0; i < len; 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);
+ bfd_write(buffer, l, 1, abfd);
+ }
+ 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->lma);
+ p = buf2;
+ while (p[0] == '0' && p[1] != 0)
+ p++;
+ sprintf (buffer, " %s $%s\r\n", s->name, p);
+ l = strlen(buffer);
+ bfd_write(buffer, l, 1,abfd);
+ }
+ }
+ sprintf(buffer, "$$ \r\n");
+ bfd_write(buffer, strlen(buffer), 1, abfd);
+ }
+}
+
+static boolean
+internal_srec_write_object_contents(abfd, symbols)
+ bfd *abfd;
+ int symbols;
+{
+ int bytes_written;
+ tdata_type *tdata = abfd->tdata.srec_data;
+ srec_data_list_type *list;
+
+ bytes_written = 0;
+
+
+ if (symbols)
+ srec_write_symbols(abfd);
+
+ srec_write_header(abfd);
+
+ /* Now wander though all the sections provided and output them */
+ list = tdata->head;
+
+ while (list != (srec_data_list_type*)NULL)
+ {
+ srec_write_section(abfd, tdata, list);
+ list = list->next;
+ }
+ srec_write_terminator(abfd, tdata);
+ return true;
+}
+
+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);
+}
+
+static int
+DEFUN(srec_sizeof_headers,(abfd, exec),
+ bfd *abfd AND
+ boolean exec)
+{
+return 0;
+}
+
+static asymbol *
+DEFUN(srec_make_empty_symbol, (abfd),
+ bfd*abfd)
+{
+ asymbol *new= (asymbol *)bfd_zalloc (abfd, sizeof (asymbol));
+ new->the_bfd = abfd;
+ return new;
+}
+
+static unsigned int
+srec_get_symtab_upper_bound(abfd)
+bfd *abfd;
+{
+ /* Read in all the info */
+ srec_get_section_contents(abfd,abfd->sections,0,0,0);
+ return (bfd_get_symcount(abfd) + 1) * (sizeof(asymbol *));
+}
+
+static unsigned int
+DEFUN(srec_get_symtab, (abfd, alocation),
+ bfd *abfd AND
+ 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;
+}
+
+void
+DEFUN(srec_get_symbol_info,(ignore_abfd, symbol, ret),
+ bfd *ignore_abfd AND
+ asymbol *symbol AND
+ symbol_info *ret)
+{
+ bfd_symbol_info (symbol, ret);
+}
+
+void
+DEFUN(srec_print_symbol,(ignore_abfd, afile, symbol, how),
+ bfd *ignore_abfd AND
+ PTR afile AND
+ asymbol *symbol AND
+ 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 FOO PROTO
+#define srec_new_section_hook (FOO(boolean, (*), (bfd *, asection *)))bfd_true
+
+#define srec_get_reloc_upper_bound (FOO(unsigned int, (*),(bfd*, asection *)))bfd_false
+#define srec_canonicalize_reloc (FOO(unsigned int, (*),(bfd*,asection *, arelent **, asymbol **))) bfd_0
+
+
+
+#define srec_openr_next_archived_file (FOO(bfd *, (*), (bfd*,bfd*))) bfd_nullvoidptr
+#define srec_find_nearest_line (FOO(boolean, (*),(bfd*,asection*,asymbol**,bfd_vma, CONST char**, CONST char**, unsigned int *))) bfd_false
+#define srec_generic_stat_arch_elt (FOO(int, (*), (bfd *,struct stat *))) bfd_0
+
+
+#define srec_core_file_failing_command (char *(*)())(bfd_nullvoidptr)
+#define srec_core_file_failing_signal (int (*)())bfd_0
+#define srec_core_file_matches_executable_p (FOO(boolean, (*),(bfd*, bfd*)))bfd_false
+#define srec_slurp_armap bfd_true
+#define srec_slurp_extended_name_table bfd_true
+#define srec_truncate_arname (void (*)())bfd_nullvoidptr
+#define srec_write_armap (FOO( boolean, (*),(bfd *, unsigned int, struct orl *, unsigned int, int))) bfd_nullvoidptr
+#define srec_get_lineno (struct lineno_cache_entry *(*)())bfd_nullvoidptr
+#define srec_close_and_cleanup bfd_generic_close_and_cleanup
+#define srec_bfd_debug_info_start bfd_void
+#define srec_bfd_debug_info_end bfd_void
+#define srec_bfd_debug_info_accumulate (FOO(void, (*), (bfd *, asection *))) bfd_void
+#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_seclet_link bfd_generic_seclet_link
+#define srec_bfd_reloc_type_lookup \
+ ((CONST struct reloc_howto_struct *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) bfd_nullvoidptr)
+#define srec_bfd_make_debug_symbol \
+ ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr)
+
+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 | DYNAMIC | 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 */
+ (struct bfd_target *(*)()) bfd_nullvoidptr,
+ (struct bfd_target *(*)()) bfd_nullvoidptr,
+ },
+ {
+ bfd_false,
+ srec_mkobject,
+ _bfd_generic_mkarchive,
+ bfd_false,
+ },
+ { /* bfd_write_contents */
+ bfd_false,
+ srec_write_object_contents,
+ _bfd_write_archive_contents,
+ bfd_false,
+ },
+ JUMP_TABLE(srec)
+ };
+
+
+
+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 | DYNAMIC | 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 */
+ (struct bfd_target *(*)()) bfd_nullvoidptr,
+ (struct bfd_target *(*)()) bfd_nullvoidptr,
+ },
+ {
+ bfd_false,
+ srec_mkobject,
+ _bfd_generic_mkarchive,
+ bfd_false,
+ },
+ { /* bfd_write_contents */
+ bfd_false,
+ symbolsrec_write_object_contents,
+ _bfd_write_archive_contents,
+ bfd_false,
+ },
+ JUMP_TABLE(srec),
+ (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..88cf850
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/stab-syms.c
@@ -0,0 +1,59 @@
+/* Table of stab names for the BFD library.
+ Copyright (C) 1990-1991 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 *
+DEFUN(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..89ac001
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/syms.c
@@ -0,0 +1,527 @@
+/* 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 trys 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 infomation 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 was read, but was 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 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 appliction which reads the symbol table:
+
+| unsigned int storage_needed;
+| asymbol **symbol_table;
+| unsigned int number_of_symbols;
+| unsigned int i;
+|
+| storage_needed = get_symtab_upper_bound (abfd);
+|
+| if (storage_needed == 0) {
+| return ;
+| }
+| symbol_table = (asymbol **) bfd_xmalloc (storage_needed);
+| ...
+| number_of_symbols =
+| bfd_canonicalize_symtab (abfd, symbol_table);
+|
+| 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, and 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 outputing 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>>. 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
+.
+. 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
+ get_symtab_upper_bound
+
+DESCRIPTION
+ Returns the number of bytes required in a vector of pointers
+ to <<asymbols>> for all the symbols in the supplied BFD,
+ including a terminal NULL pointer. If there are no symbols in
+ the BFD, then 0 is returned.
+
+.#define get_symtab_upper_bound(abfd) \
+. BFD_SEND (abfd, _get_symtab_upper_bound, (abfd))
+
+*/
+
+/*
+FUNCTION
+ bfd_canonicalize_symtab
+
+DESCRIPTION
+ Supplied a BFD and a pointer to an uninitialized vector of
+ pointers. This reads in the symbols from the BFD, and fills in
+ the table with pointers to the symbols, and a trailing NULL.
+ The routine returns 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
+
+DESCRIPTION
+ Provided a table of pointers to symbols and a count, writes to
+ the output BFD the symbols when closed.
+
+SYNOPSIS
+ boolean bfd_set_symtab (bfd *, asymbol **, unsigned int );
+*/
+
+boolean
+bfd_set_symtab (abfd, location, symcount)
+ bfd *abfd;
+ asymbol **location;
+ unsigned int symcount;
+{
+ if ((abfd->format != bfd_object) || (bfd_read_p (abfd))) {
+ bfd_error = invalid_operation;
+ return false;
+ }
+
+ bfd_get_outsymbols (abfd) = location;
+ bfd_get_symcount (abfd) = symcount;
+ return true;
+}
+
+/*
+FUNCTION
+ bfd_print_symbol_vandf
+
+DESCRIPTION
+ Prints the value and flags of the symbol supplied to the stream file.
+
+SYNOPSIS
+ void bfd_print_symbol_vandf(PTR file, asymbol *symbol);
+*/
+void
+DEFUN(bfd_print_symbol_vandf,(file, symbol),
+PTR file AND
+asymbol *symbol)
+{
+ flagword type = symbol->flags;
+ if (symbol->section != (asection *)NULL)
+ {
+ fprintf_vma(file, symbol->value+symbol->section->vma);
+ }
+ else
+ {
+ fprintf_vma(file, symbol->value);
+ }
+ 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' :' ');
+
+}
+
+
+/*
+FUNCTION
+ bfd_make_empty_symbol
+
+DESCRIPTION
+ This function creates a new <<asymbol>> structure for the BFD,
+ and returns a pointer to it.
+
+ This routine is necessary, since 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
+ This function creates a new <<asymbol>> structure for the BFD,
+ 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 COFF 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
+ COFF 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 symbol, or '?' for an unknown class.
+
+SYNOPSIS
+ int bfd_decode_symclass(asymbol *symbol);
+*/
+int
+DEFUN(bfd_decode_symclass,(symbol),
+asymbol *symbol)
+{
+ char c;
+
+ if (bfd_is_com_section (symbol->section))
+ return 'C';
+ if (symbol->section == &bfd_und_section)
+ return 'U';
+ if (symbol->section == &bfd_ind_section)
+ return 'I';
+ if (!(symbol->flags & (BSF_GLOBAL|BSF_LOCAL)))
+ return '?';
+
+ if (symbol->section == &bfd_abs_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
+DEFUN(bfd_symbol_info,(symbol, ret),
+ asymbol *symbol AND
+ 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..dd7328b
--- /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. */
+
+#ifdef __bsdi__
+/* This seems to be the right thing for BSDI. */
+#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..d6a9665
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/targets.c
@@ -0,0 +1,635 @@
+/* Generic target-file-type support for the BFD library.
+ 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. */
+
+#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 First a BFD is created by calling the internal routine
+ <<new_bfd>>, then <<bfd_find_target>> is called 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>>,
+ it looks up the environment variable <<GNUTARGET>> and uses
+ that as the target string.
+
+ o If the target string is still NULL, or the target string is
+ <<default>>, then the first item in the target vector is used
+ as the target type, and <<target_defaulted>> is set to
+ cause <<bfd_check_format>> to loop through all the targets.
+ @xref{bfd_target}. @xref{Formats}.
+
+ o Otherwise, the elements in the target vector are inspected
+ one by one, until a match on target name is found. When found,
+ that is used.
+
+ o Otherwise the error <<invalid_target>> is returned 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. The
+ routine returns <<true>> when the application 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, what
+ routines to call to do various operations, etc.
+
+ Every BFD points to a target structure with its <<xvec>>
+ member.
+
+ These macros 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 "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)
+
+ For operations which index on the BFD format
+
+.#define BFD_SEND_FMT(bfd, message, arglist) \
+. (((bfd)->xvec->message[(int)((bfd)->format)]) arglist)
+
+ This is the struct 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!
+
+.typedef struct bfd_target
+.{
+
+Identifies the kind of target, eg SunOS4, Ultrix, etc.
+
+. char *name;
+
+The "flavour" of a back end is a general indication about the contents
+of a file.
+
+. enum target_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_hppa_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;
+
+This is a mask of all the flags which an executable may have set -
+from the set <<NO_FLAGS>>, <<HAS_RELOC>>, ...<<D_PAGED>>.
+
+. flagword object_flags;
+
+This is 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 filenames 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 to the other
+entry points, since they don't take BFD as first arg. Certain other handlers
+could do the same.
+
+. bfd_vma (*bfd_getx64) PARAMS ((bfd_byte *));
+. bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((bfd_byte *));
+. void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *));
+. bfd_vma (*bfd_getx32) PARAMS ((bfd_byte *));
+. bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((bfd_byte *));
+. void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *));
+. bfd_vma (*bfd_getx16) PARAMS ((bfd_byte *));
+. bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((bfd_byte *));
+. void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *));
+
+Byte swapping for the headers
+
+. bfd_vma (*bfd_h_getx64) PARAMS ((bfd_byte *));
+. bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((bfd_byte *));
+. void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *));
+. bfd_vma (*bfd_h_getx32) PARAMS ((bfd_byte *));
+. bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((bfd_byte *));
+. void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *));
+. bfd_vma (*bfd_h_getx16) PARAMS ((bfd_byte *));
+. bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((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 bfd_target * or zero.
+
+. 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 following functions are defined in <<JUMP_TABLE>>. The idea is
+that the back end writer of <<foo>> names all the routines
+<<foo_>>@var{entry_point}, <<JUMP_TABLE>> will built the entries
+in this structure in the right order.
+
+Core file entry points
+
+. 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
+
+. 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));
+
+Standard stuff.
+
+. boolean (*_close_and_cleanup) PARAMS ((bfd *));
+. boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+. file_ptr, bfd_size_type));
+. boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR,
+. file_ptr, bfd_size_type));
+. boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr));
+
+Symbols and relocations
+
+. unsigned int (*_get_symtab_upper_bound) PARAMS ((bfd *));
+. unsigned int (*_bfd_canonicalize_symtab) PARAMS ((bfd *,
+. struct symbol_cache_entry **));
+. unsigned int (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr));
+. unsigned int (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **,
+. 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))
+
+. alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *));
+.
+. boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture,
+. unsigned long));
+.
+. bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev));
+.
+. 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));
+.
+. int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *));
+.
+. int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean));
+.
+. void (*_bfd_debug_info_start) PARAMS ((bfd *));
+. void (*_bfd_debug_info_end) PARAMS ((bfd *));
+. void (*_bfd_debug_info_accumulate) PARAMS ((bfd *, struct sec *));
+.
+. bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *,
+. struct bfd_seclet *, bfd_byte *data,
+. boolean relocateable));
+.
+. boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *,
+. struct symbol_cache_entry **));
+.
+. boolean (*_bfd_seclet_link) PARAMS ((bfd *, PTR data,
+. boolean relocateable));
+
+. {* See documentation on reloc types. *}
+. CONST struct reloc_howto_struct *
+. (*reloc_type_lookup) PARAMS ((bfd *abfd,
+. bfd_reloc_code_real_type code));
+.
+. {* 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));
+
+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 bfd_target a29kcoff_big_vec;
+extern bfd_target a_out_adobe_vec;
+extern bfd_target aout_mips_big_vec;
+extern bfd_target aout_mips_little_vec;
+extern bfd_target apollocoff_vec;
+extern bfd_target b_out_vec_big_host;
+extern bfd_target b_out_vec_little_host;
+extern bfd_target bfd_elf32_big_generic_vec;
+extern bfd_target bfd_elf32_bigmips_vec;
+extern bfd_target bfd_elf32_hppa_vec;
+extern bfd_target bfd_elf32_i386_vec;
+extern bfd_target bfd_elf32_i860_vec;
+extern bfd_target bfd_elf32_little_generic_vec;
+extern bfd_target bfd_elf32_littlemips_vec;
+extern bfd_target bfd_elf32_m68k_vec;
+extern bfd_target bfd_elf32_m88k_vec;
+extern bfd_target bfd_elf32_sparc_vec;
+extern bfd_target bfd_elf64_big_generic_vec;
+extern bfd_target bfd_elf64_little_generic_vec;
+extern bfd_target demo_64_vec;
+extern bfd_target ecoff_big_vec;
+extern bfd_target ecoff_little_vec;
+extern bfd_target ecoffalpha_little_vec;
+extern bfd_target h8300coff_vec;
+extern bfd_target h8500coff_vec;
+extern bfd_target host_aout_vec;
+extern bfd_target hp300bsd_vec;
+extern bfd_target hp300hpux_vec;
+extern bfd_target hppa_vec;
+extern bfd_target i386aout_vec;
+extern bfd_target i386bsd_vec;
+extern bfd_target netbsd386_vec;
+extern bfd_target freebsd386_vec;
+extern bfd_target i386coff_vec;
+extern bfd_target i386linux_vec;
+extern bfd_target i386lynx_aout_vec;
+extern bfd_target i386lynx_coff_vec;
+extern bfd_target icoff_big_vec;
+extern bfd_target icoff_little_vec;
+extern bfd_target ieee_vec;
+extern bfd_target m68kcoff_vec;
+extern bfd_target m68kcoffun_vec;
+extern bfd_target m68klynx_aout_vec;
+extern bfd_target m68klynx_coff_vec;
+extern bfd_target m88kbcs_vec;
+extern bfd_target newsos3_vec;
+extern bfd_target nlm32_big_generic_vec;
+extern bfd_target nlm32_i386_vec;
+extern bfd_target nlm32_little_generic_vec;
+extern bfd_target nlm64_big_generic_vec;
+extern bfd_target nlm64_little_generic_vec;
+extern bfd_target oasys_vec;
+extern bfd_target rs6000coff_vec;
+extern bfd_target shcoff_vec;
+extern bfd_target sunos_big_vec;
+extern bfd_target tekhex_vec;
+extern bfd_target we32kcoff_vec;
+extern bfd_target z8kcoff_vec;
+
+/* srec is always included. */
+extern bfd_target srec_vec;
+extern bfd_target symbolsrec_vec;
+
+/* All of the xvecs for core files. */
+extern bfd_target aix386_core_vec;
+extern bfd_target hpux_core_vec;
+extern bfd_target osf_core_vec;
+extern bfd_target sco_core_vec;
+extern bfd_target trad_core_vec;
+
+bfd_target *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,
+#if 0 /* No one seems to use this. */
+ &bfd_elf32_big_generic_vec,
+ &bfd_elf32_bigmips_vec,
+#endif
+#if 0
+ &bfd_elf32_hppa_vec,
+#endif
+ &bfd_elf32_i386_vec,
+ &bfd_elf32_i860_vec,
+#if 0 /* No one seems to use this. */
+ &bfd_elf32_little_generic_vec,
+ &bfd_elf32_littlemips_vec,
+#endif
+ &bfd_elf32_m68k_vec,
+ &bfd_elf32_m88k_vec,
+ &bfd_elf32_sparc_vec,
+#ifdef BFD64 /* No one seems to use this. */
+ &bfd_elf64_big_generic_vec,
+ &bfd_elf64_little_generic_vec,
+#endif
+#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
+ &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)
+ &hppa_vec,
+#endif
+ &i386aout_vec,
+ &i386bsd_vec,
+ &netbsd386_vec,
+ &freebsd386_vec,
+ &i386coff_vec,
+#if 0
+ &i386linux_vec,
+#endif
+ &i386lynx_aout_vec,
+ &i386lynx_coff_vec,
+ &icoff_big_vec,
+ &icoff_little_vec,
+ &ieee_vec,
+ &m68kcoff_vec,
+ &m68kcoffun_vec,
+ &m68klynx_aout_vec,
+ &m68klynx_coff_vec,
+ &m88kbcs_vec,
+ &newsos3_vec,
+#if 0 /* No one seems to use this. */
+ &nlm32_big_generic_vec,
+#endif
+ &nlm32_i386_vec,
+#if 0 /* No one seems to use this. */
+ &nlm32_little_generic_vec,
+#endif
+#ifdef BFD64
+ &nlm64_big_generic_vec,
+ &nlm64_little_generic_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
+ &rs6000coff_vec,
+ &shcoff_vec,
+ &sunos_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 OSF_CORE
+ &osf_core_vec,
+#endif
+#ifdef SCO_CORE
+ &sco_core_vec,
+#endif
+#ifdef TRAD_CORE
+ &trad_core_vec,
+#endif
+
+ NULL /* end of list marker */
+};
+
+/* default_vector[0] contains either the address of the default vector,
+ if there is one, or zero if there isn't. */
+
+bfd_target *default_vector[] = {
+#ifdef DEFAULT_VECTOR
+ &DEFAULT_VECTOR,
+#endif
+ NULL
+};
+
+
+
+
+/*
+FUNCTION
+ bfd_find_target
+
+DESCRIPTION
+ Returns a pointer to the transfer vector for the object target
+ named target_name. If target_name is NULL, chooses the one in
+ the environment variable GNUTARGET; if that is null or not
+ defined thenthe first entry in the target list is chosen.
+ 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.
+
+SYNOPSIS
+ bfd_target *bfd_find_target(CONST char *, bfd *);
+*/
+
+bfd_target *
+DEFUN(bfd_find_target,(target_name, abfd),
+ CONST char *target_name AND
+ bfd *abfd)
+{
+ bfd_target **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 = target_vector[0];
+ }
+
+ abfd->target_defaulted = false;
+
+ for (target = &target_vector[0]; *target != NULL; target++) {
+ if (!strcmp (targname, (*target)->name))
+ return abfd->xvec = *target;
+ }
+
+ bfd_error = invalid_target;
+ return NULL;
+}
+
+
+/*
+FUNCTION
+ bfd_target_list
+
+DESCRIPTION
+ This function returns a freshly malloced NULL-terminated
+ vector of the names of all the valid BFD targets. Do not
+ modify the names
+
+SYNOPSIS
+ CONST char **bfd_target_list(void);
+
+*/
+
+CONST char **
+DEFUN_VOID(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
+ bfd_target **target;
+ CONST char **name_list, **name_ptr;
+
+ for (target = &target_vector[0]; *target != NULL; target++)
+ vec_length++;
+
+ name_ptr =
+ name_list = (CONST char **) zalloc ((vec_length + 1) * sizeof (char **));
+
+ if (name_list == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+
+ for (target = &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..203c80e
--- /dev/null
+++ b/gnu/usr.bin/gdb/bfd/trad-core.c
@@ -0,0 +1,384 @@
+/* BFD back end for traditional Unix core files (U-area and raw sections)
+ Copyright 1988, 1989, 1991, 1992, 1993 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 */
+
+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 */
+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_error = wrong_format;
+ return 0;
+ }
+
+ /* Sanity check perhaps??? */
+ if (u.u_dsize > 0x1000000) /* Remember, it's in pages... */
+ {
+ bfd_error = wrong_format;
+ return 0;
+ }
+ if (u.u_ssize > 0x1000000)
+ {
+ 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_error = system_call_error;
+ return 0;
+ }
+ if (NBPG * (UPAGES + u.u_dsize + u.u_ssize) > statbuf.st_size)
+ {
+ bfd_error = file_truncated;
+ return 0;
+ }
+ 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_error = wrong_format;
+ return 0;
+ }
+ }
+
+ /* 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_zalloc (abfd, sizeof (struct trad_core_struct));
+ if (rawptr == NULL) {
+ 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 *) zalloc (sizeof (asection));
+ if (core_stacksec (abfd) == NULL) {
+ loser:
+ bfd_error = no_memory;
+ free ((void *)rawptr);
+ return 0;
+ }
+ core_datasec (abfd) = (asection *) zalloc (sizeof (asection));
+ if (core_datasec (abfd) == NULL) {
+ loser1:
+ free ((void *)core_stacksec (abfd));
+ goto loser;
+ }
+ core_regsec (abfd) = (asection *) zalloc (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_ALLOC + SEC_HAS_CONTENTS;
+
+ core_datasec (abfd)->_raw_size = NBPG * u.u_dsize;
+ 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
+/* a hack, but it works for FreeBSD !! */
+#include <vm/vm_param.h>
+/* this should really be in <vm/vm_param.h>, but somebody forgot it */
+#ifndef vm_page_size
+#define vm_page_size 4096
+#endif
+#define HOST_STACK_START_ADDR trunc_page(u.u_kproc.kp_eproc.e_vm.vm_maxsaddr \
++ MAXSSIZ - ctob(u.u_ssize))
+#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;
+#ifdef TRAD_CORE_STACK_FILEPOS
+ core_stacksec (abfd)->filepos = TRAD_CORE_STACK_FILEPOS;
+#else
+ core_stacksec (abfd)->filepos = (NBPG * UPAGES) + NBPG * u.u_dsize;
+#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 */
+}
+
+/* No archive file support via this BFD */
+#define trad_unix_openr_next_archived_file bfd_generic_openr_next_archived_file
+#define trad_unix_generic_stat_arch_elt bfd_generic_stat_arch_elt
+#define trad_unix_slurp_armap bfd_false
+#define trad_unix_slurp_extended_name_table bfd_true
+#define trad_unix_write_armap (boolean (*) PARAMS \
+ ((bfd *arch, unsigned int elength, struct orl *map, \
+ unsigned int orl_count, int stridx))) bfd_false
+#define trad_unix_truncate_arname bfd_dont_truncate_arname
+#define aout_32_openr_next_archived_file bfd_generic_openr_next_archived_file
+
+#define trad_unix_close_and_cleanup bfd_generic_close_and_cleanup
+#define trad_unix_set_section_contents (boolean (*) PARAMS \
+ ((bfd *abfd, asection *section, PTR data, file_ptr offset, \
+ bfd_size_type count))) bfd_false
+#define trad_unix_get_section_contents bfd_generic_get_section_contents
+#define trad_unix_new_section_hook (boolean (*) PARAMS \
+ ((bfd *, sec_ptr))) bfd_true
+#define trad_unix_get_symtab_upper_bound bfd_0u
+#define trad_unix_get_symtab (unsigned int (*) PARAMS \
+ ((bfd *, struct symbol_cache_entry **))) bfd_0u
+#define trad_unix_get_reloc_upper_bound (unsigned int (*) PARAMS \
+ ((bfd *, sec_ptr))) bfd_0u
+#define trad_unix_canonicalize_reloc (unsigned int (*) PARAMS \
+ ((bfd *, sec_ptr, arelent **, struct symbol_cache_entry**))) bfd_0u
+#define trad_unix_make_empty_symbol (struct symbol_cache_entry * \
+ (*) PARAMS ((bfd *))) bfd_false
+#define trad_unix_print_symbol (void (*) PARAMS \
+ ((bfd *, PTR, struct symbol_cache_entry *, \
+ bfd_print_symbol_type))) bfd_false
+#define trad_unix_get_symbol_info (void (*) PARAMS \
+ ((bfd *, struct symbol_cache_entry *, \
+ symbol_info *))) bfd_false
+#define trad_unix_get_lineno (alent * (*) PARAMS \
+ ((bfd *, struct symbol_cache_entry *))) bfd_nullvoidptr
+#define trad_unix_set_arch_mach (boolean (*) PARAMS \
+ ((bfd *, enum bfd_architecture, unsigned long))) bfd_false
+#define trad_unix_find_nearest_line (boolean (*) PARAMS \
+ ((bfd *abfd, struct sec *section, \
+ struct symbol_cache_entry **symbols,bfd_vma offset, \
+ CONST char **file, CONST char **func, unsigned int *line))) bfd_false
+#define trad_unix_sizeof_headers (int (*) PARAMS \
+ ((bfd *, boolean))) bfd_0
+
+#define trad_unix_bfd_debug_info_start bfd_void
+#define trad_unix_bfd_debug_info_end bfd_void
+#define trad_unix_bfd_debug_info_accumulate (void (*) PARAMS \
+ ((bfd *, struct sec *))) bfd_void
+#define trad_unix_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
+#define trad_unix_bfd_relax_section bfd_generic_relax_section
+#define trad_unix_bfd_seclet_link \
+ ((boolean (*) PARAMS ((bfd *, PTR, boolean))) bfd_false)
+#define trad_unix_bfd_reloc_type_lookup \
+ ((CONST struct reloc_howto_struct *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) bfd_nullvoidptr)
+#define trad_unix_bfd_make_debug_symbol \
+ ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr)
+
+/* 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 (( bfd_byte *))) swap_abort )
+#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort )
+#define NO_SIGNED_GET ((bfd_signed_vma (*) PARAMS ((bfd_byte *))) swap_abort )
+
+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 | DYNAMIC | 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
+ },
+
+ JUMP_TABLE(trad_unix),
+ (PTR) 0 /* backend_data */
+};
diff --git a/gnu/usr.bin/gdb/blockframe.c b/gnu/usr.bin/gdb/blockframe.c
new file mode 100644
index 0000000..236d1cd
--- /dev/null
+++ b/gnu/usr.bin/gdb/blockframe.c
@@ -0,0 +1,622 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)blockframe.c 6.4 (Berkeley) 5/11/91";
+#endif /* not lint */
+
+/* Get info from stack frames;
+ convert between frames, blocks, functions and pc values.
+ Copyright (C) 1986, 1987, 1988, 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. */
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+
+#include <obstack.h>
+
+#if defined(NEWVM) && defined(KERNELDEBUG)
+#include <sys/param.h> /* XXX for FRAME_CHAIN_VALID */
+#endif
+
+/* Start and end of object file containing the entry point.
+ STARTUP_FILE_END is the first address of the next file.
+ 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. */
+CORE_ADDR startup_file_start;
+CORE_ADDR startup_file_end;
+
+/* Is ADDR outside the startup file? */
+int
+outside_startup_file (addr)
+ CORE_ADDR addr;
+{
+ return !(addr >= startup_file_start && addr < startup_file_end);
+}
+
+/* Address of innermost stack frame (contents of FP register) */
+
+static FRAME current_frame;
+
+struct block *block_for_pc ();
+CORE_ADDR get_pc_function_start ();
+
+/*
+ * 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 */
+
+ 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->next_frame = 0; /* Since arbitrary */
+ fci->pc = pc;
+
+#ifdef INIT_EXTRA_FRAME_INFO
+ INIT_EXTRA_FRAME_INFO (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 */
+}
+
+/* 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. */
+
+/* Many machines which allow frameless functions can detect them using
+ this macro. Such machines should define FRAMELESS_FUNCTION_INVOCATION
+ to just call this macro. */
+#define FRAMELESS_LOOK_FOR_PROLOGUE(FI, FRAMELESS) \
+{ \
+ CORE_ADDR func_start, after_prologue; \
+ func_start = (get_pc_function_start ((FI)->pc) + \
+ FUNCTION_START_OFFSET); \
+ if (func_start) \
+ { \
+ after_prologue = func_start; \
+ SKIP_PROLOGUE (after_prologue); \
+ (FRAMELESS) = (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. */ \
+ (FRAMELESS) = 0; \
+}
+
+/* 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;
+ struct frame_info *prev;
+ int fromleaf = 0;
+
+ /* 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 (!current_frame)
+ {
+ if (!have_inferior_p () && !have_core_file_p ())
+ fatal ("get_prev_frame_info: Called before cache primed. \"Shouldn't happen.\"");
+ else
+ error ("No inferior or core file.");
+ }
+
+ 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 param.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;
+ /* If this frame is a leaf, this will be superceeded by the
+ code below. */
+ 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->next_frame = prev->next ? prev->next->frame : 0;
+
+#ifdef INIT_EXTRA_FRAME_INFO
+ INIT_EXTRA_FRAME_INFO(prev);
+#endif
+
+ /* This entry is in the frame queue now, which is good since
+ FRAME_SAVED_PC may use that queue to figure out it's value
+ (see m-sparc.h). We want the pc saved in the inferior frame. */
+ prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (next_frame) :
+ next_frame ? FRAME_SAVED_PC (next_frame) : read_pc ());
+
+ return prev;
+}
+
+CORE_ADDR
+get_frame_pc (frame)
+ FRAME frame;
+{
+ struct frame_info *fi;
+ fi = get_frame_info (frame);
+ return fi->pc;
+}
+
+/* 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);
+}
+
+/* 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_frame != 0)
+ /* We are not in the innermost frame. 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 = block_for_pc (pc);
+ register struct symbol *symbol;
+ if (bl == 0 || (symbol = block_function (bl)) == 0)
+ {
+ register int misc_index = find_pc_misc_function (pc);
+ if (misc_index >= 0)
+ return misc_function_vector[misc_index].address;
+ return 0;
+ }
+ bl = SYMBOL_BLOCK_VALUE (symbol);
+ return BLOCK_START (bl);
+}
+
+/* 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 innermost lexical block containing the specified pc value,
+ or 0 if there is none. */
+
+extern struct symtab *psymtab_to_symtab ();
+
+struct block *
+block_for_pc (pc)
+ register CORE_ADDR pc;
+{
+ register struct block *b;
+ register int bot, top, half;
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ struct blockvector *bl;
+
+ /* First search all symtabs for one whose file contains our pc */
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ bl = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bl, 0);
+ if (BLOCK_START (b) <= pc
+ && BLOCK_END (b) > pc)
+ break;
+ }
+
+ if (s == 0)
+ for (ps = partial_symtab_list; ps; ps = ps->next)
+ {
+ if (ps->textlow <= pc
+ && ps->texthigh > pc)
+ {
+ if (ps->readin)
+ fatal ("Internal error: pc found in readin psymtab and not in any symtab.");
+ s = psymtab_to_symtab (ps);
+ bl = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bl, 0);
+ break;
+ }
+ }
+
+ if (s == 0)
+ return 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)
+ return b;
+ bot--;
+ }
+
+ 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);
+}
+
+/* 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-zero.
+ Returns 0 if it couldn't find anything, 1 if it did. On a zero
+ return, *NAME and *ADDRESS are always set to zero. On a 1 return,
+ *NAME and *ADDRESS contain real information. */
+
+int
+find_pc_partial_function (pc, name, address)
+ CORE_ADDR pc;
+ char **name;
+ CORE_ADDR *address;
+{
+ struct partial_symtab *pst = find_pc_psymtab (pc);
+ struct symbol *f;
+ int miscfunc;
+ struct partial_symbol *psb;
+
+ if (pst)
+ {
+ if (pst->readin)
+ {
+ /* The information we want has already been read in.
+ We can go to the already readin symbols and we'll get
+ the best possible answer. */
+ f = find_pc_function (pc);
+ if (!f)
+ {
+ return_error:
+ /* No availible symbol. */
+ if (name != 0)
+ *name = 0;
+ if (address != 0)
+ *address = 0;
+ return 0;
+ }
+
+ if (name)
+ *name = SYMBOL_NAME (f);
+ if (address)
+ *address = BLOCK_START (SYMBOL_BLOCK_VALUE (f));
+ return 1;
+ }
+
+ /* Get the information from a combination of the pst
+ (static symbols), and the misc function vector (extern
+ symbols). */
+ miscfunc = find_pc_misc_function (pc);
+ psb = find_pc_psymbol (pst, pc);
+
+ if (!psb && miscfunc == -1)
+ {
+ goto return_error;
+ }
+ if (!psb
+ || (miscfunc != -1
+ && (SYMBOL_VALUE(psb)
+ < misc_function_vector[miscfunc].address)))
+ {
+ if (address)
+ *address = misc_function_vector[miscfunc].address;
+ if (name)
+ *name = misc_function_vector[miscfunc].name;
+ return 1;
+ }
+ else
+ {
+ if (address)
+ *address = SYMBOL_VALUE (psb);
+ if (name)
+ *name = SYMBOL_NAME (psb);
+ return 1;
+ }
+ }
+ else
+ /* Must be in the misc function stuff. */
+ {
+ miscfunc = find_pc_misc_function (pc);
+ if (miscfunc == -1)
+ goto return_error;
+ if (address)
+ *address = misc_function_vector[miscfunc].address;
+ if (name)
+ *name = misc_function_vector[miscfunc].name;
+ return 1;
+ }
+}
+
+/* Find the misc function whose address is the largest
+ while being less than PC. Return its index in misc_function_vector.
+ Returns -1 if PC is not in suitable range. */
+
+int
+find_pc_misc_function (pc)
+ register CORE_ADDR pc;
+{
+ register int lo = 0;
+ register int hi = misc_function_count-1;
+ register int new;
+ register int distance;
+
+ /* Note that the last thing in the vector is always _etext. */
+ /* Actually, "end", now that non-functions
+ go on the misc_function_vector. */
+
+ /* Above statement is not *always* true - fix for case where there are */
+ /* no misc functions at all (ie no symbol table has been read). */
+ if (hi < 0) return -1; /* no misc functions recorded */
+
+ /* trivial reject range test */
+ if (pc < misc_function_vector[0].address ||
+ pc > misc_function_vector[hi].address)
+ return -1;
+
+ /* Note that the following search will not return hi if
+ pc == misc_function_vector[hi].address. If "end" points to the
+ first unused location, this is correct and the above test
+ simply needs to be changed to
+ "pc >= misc_function_vector[hi].address". */
+ do {
+ new = (lo + hi) >> 1;
+ distance = misc_function_vector[new].address - pc;
+ if (distance == 0)
+ return new; /* an exact match */
+ else if (distance > 0)
+ hi = new;
+ else
+ lo = new;
+ } while (hi-lo != 1);
+
+ /* if here, we had no exact match, so return the lower choice */
+ return lo;
+}
+
+/* Return the innermost stack frame executing inside of the specified block,
+ or zero if there is no such frame. */
+
+FRAME
+block_innermost_frame (block)
+ struct block *block;
+{
+ struct frame_info *fi;
+ register FRAME frame;
+ register CORE_ADDR start = BLOCK_START (block);
+ register CORE_ADDR 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;
+ }
+}
+
+void
+_initialize_blockframe ()
+{
+ obstack_init (&frame_cache_obstack);
+}
diff --git a/gnu/usr.bin/gdb/breakpoint.c b/gnu/usr.bin/gdb/breakpoint.c
new file mode 100644
index 0000000..b515ed3
--- /dev/null
+++ b/gnu/usr.bin/gdb/breakpoint.c
@@ -0,0 +1,1383 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)breakpoint.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Everything about breakpoints, for GDB.
+ 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. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+
+/* This is the sequence of bytes we insert for a breakpoint. */
+
+static char break_insn[] = BREAKPOINT;
+
+/* States of enablement of breakpoint.
+ `temporary' means disable when hit.
+ `delete' means delete when hit. */
+
+enum enable { disabled, enabled, temporary, delete};
+
+/* Not 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 */
+
+struct breakpoint
+{
+ struct breakpoint *next;
+ /* Number assigned to distinguish breakpoints. */
+ int number;
+ /* Address to break at. */
+ CORE_ADDR address;
+ /* Line number of this address. Redundant. */
+ int line_number;
+ /* Symtab of file of this address. Redundant. */
+ struct symtab *symtab;
+ /* Zero means disabled; remember the info but don't break here. */
+ enum enable enable;
+ /* 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. */
+ char shadow_contents[sizeof break_insn];
+ /* Nonzero if this breakpoint is now inserted. */
+ char inserted;
+ /* Nonzero if this is not the first breakpoint in the list
+ for the given address. */
+ 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;
+};
+
+#define ALL_BREAKPOINTS(b) for (b = breakpoint_chain; b; b = b->next)
+
+/* Chain of all breakpoints defined. */
+
+struct breakpoint *breakpoint_chain;
+
+/* Number of last breakpoint made. */
+
+static int breakpoint_count;
+
+/* 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;
+
+/* Remaining commands (not yet executed)
+ of last breakpoint hit. */
+
+struct command_line *breakpoint_commands;
+
+static void delete_breakpoint ();
+void clear_momentary_breakpoints ();
+void breakpoint_auto_delete ();
+
+/* Flag indicating extra verbosity for xgdb. */
+extern int xgdb_verbose;
+
+/* 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;
+ register char *p;
+ register int bnum;
+ register struct expression *expr;
+
+ if (arg == 0)
+ error_no_arg ("breakpoint number");
+
+ p = arg;
+ while (*p >= '0' && *p <= '9') p++;
+ if (p == arg)
+ /* There is no number here. (e.g. "cond a == b"). */
+ error_no_arg ("breakpoint number");
+ bnum = atoi (arg);
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == bnum)
+ {
+ if (b->cond)
+ {
+ free (b->cond);
+ b->cond = 0; /* parse_c_1 can leave this unchanged. */
+ }
+ if (*p == 0)
+ {
+ b->cond = 0;
+ if (from_tty)
+ printf ("Breakpoint %d now unconditional.\n", bnum);
+ }
+ else
+ {
+ if (*p != ' ' && *p != '\t')
+ error ("Arguments must be an integer (breakpoint number) and an expression.");
+
+ /* Find start of expression */
+ while (*p == ' ' || *p == '\t') p++;
+
+ arg = p;
+ b->cond = (struct expression *) parse_c_1 (&arg, block_for_pc (b->address), 0);
+ if (*arg)
+ error ("Junk at end of expression");
+ }
+ return;
+ }
+
+ error ("No breakpoint number %d.", bnum);
+}
+
+static void
+commands_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register struct breakpoint *b;
+ register char *p, *p1;
+ 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 (breakpoint_commands)
+ error ("Can't use the \"commands\" command among a breakpoint's commands.");
+
+ /* Allow commands by itself to refer to the last breakpoint. */
+ if (arg == 0)
+ bnum = breakpoint_count;
+ else
+ {
+ p = arg;
+ if (! (*p >= '0' && *p <= '9'))
+ error ("Argument must be integer (a breakpoint number).");
+
+ while (*p >= '0' && *p <= '9') p++;
+ if (*p)
+ error ("Unexpected extra arguments following breakpoint number.");
+
+ bnum = atoi (arg);
+ }
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == bnum)
+ {
+ if (from_tty && input_from_terminal_p ())
+ {
+ printf ("Type commands for when breakpoint %d is hit, one per line.\n\
+End with a line saying just \"end\".\n", bnum);
+ fflush (stdout);
+ }
+ l = read_command_lines (from_tty);
+ free_command_lines (b->commands);
+ b->commands = l;
+ return;
+ }
+ error ("No breakpoint number %d.", bnum);
+}
+
+/* Called from command loop to execute the commands
+ associated with the breakpoint we just stopped at. */
+
+void
+do_breakpoint_commands ()
+{
+ struct command_line *cmd;
+
+ while (cmd = breakpoint_commands)
+ {
+ breakpoint_commands = 0;
+ execute_command_lines(cmd);
+ /* If command was "cont", breakpoint_commands is now 0,
+ of if we stopped at yet another breakpoint which has commands,
+ it is now the commands for the new breakpoint. */
+ }
+ clear_momentary_breakpoints ();
+}
+
+/* Used when the program is proceeded, to eliminate any remaining
+ commands attached to the previous breakpoint we stopped at. */
+
+void
+clear_breakpoint_commands ()
+{
+ breakpoint_commands = 0;
+ breakpoint_auto_delete (0);
+}
+
+/* Functions to get and set the current list of pending
+ breakpoint commands. These are used by run_stack_dummy
+ to preserve the commands around a function call. */
+
+struct command_line *
+get_breakpoint_commands ()
+{
+ return breakpoint_commands;
+}
+
+void
+set_breakpoint_commands (cmds)
+ struct command_line *cmds;
+{
+ breakpoint_commands = cmds;
+}
+
+/* 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;
+
+#ifdef BREAKPOINT_DEBUG
+ printf ("Inserting breakpoints.\n");
+#endif /* BREAKPOINT_DEBUG */
+
+ ALL_BREAKPOINTS (b)
+ if (b->enable != disabled && ! b->inserted && ! b->duplicate)
+ {
+ read_memory (b->address, b->shadow_contents, sizeof break_insn);
+ val = write_memory (b->address, break_insn, sizeof break_insn);
+ if (val)
+ return val;
+#ifdef BREAKPOINT_DEBUG
+ printf ("Inserted breakpoint at 0x%x, shadow 0x%x, 0x%x.\n",
+ b->address, b->shadow_contents[0], b->shadow_contents[1]);
+#endif /* BREAKPOINT_DEBUG */
+ b->inserted = 1;
+ }
+ return 0;
+}
+
+int
+remove_breakpoints ()
+{
+ register struct breakpoint *b;
+ int val;
+
+#ifdef BREAKPOINT_DEBUG
+ printf ("Removing breakpoints.\n");
+#endif /* BREAKPOINT_DEBUG */
+
+ ALL_BREAKPOINTS (b)
+ if (b->inserted)
+ {
+ val = write_memory (b->address, b->shadow_contents, sizeof break_insn);
+ if (val)
+ return val;
+ b->inserted = 0;
+#ifdef BREAKPOINT_DEBUG
+ printf ("Removed breakpoint at 0x%x, shadow 0x%x, 0x%x.\n",
+ b->address, b->shadow_contents[0], b->shadow_contents[1]);
+#endif /* BREAKPOINT_DEBUG */
+ }
+
+ return 0;
+}
+
+/* Clear the "inserted" flag in all breakpoints.
+ This is done when the inferior is loaded. */
+
+void
+mark_breakpoints_out ()
+{
+ register struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ b->inserted = 0;
+}
+
+/* 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;
+}
+
+/* Evaluate the expression EXP and return 1 if value is zero.
+ This is used inside a catch_errors to evaluate the breakpoint condition. */
+
+int
+breakpoint_cond_eval (exp)
+ struct expression *exp;
+{
+ return value_zerop (evaluate_expression (exp));
+}
+
+/* Return 0 if PC is not the address just after a breakpoint,
+ or -1 if breakpoint says do not stop now,
+ or -2 if breakpoint says it has deleted itself and don't stop,
+ or -3 if hit a breakpoint number -3 (delete when program stops),
+ or else the number of the breakpoint,
+ with 0x1000000 added (or subtracted, for a negative return value) for
+ a silent breakpoint. */
+
+int
+breakpoint_stop_status (pc, frame_address)
+ CORE_ADDR pc;
+ FRAME_ADDR frame_address;
+{
+ register struct breakpoint *b;
+ register int cont = 0;
+
+ /* Get the address where the breakpoint would have been. */
+ pc -= DECR_PC_AFTER_BREAK;
+
+ ALL_BREAKPOINTS (b)
+ if (b->enable != disabled && b->address == pc)
+ {
+ if (b->frame && b->frame != frame_address)
+ cont = -1;
+ else
+ {
+ int value_zero;
+ 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_zero
+ = catch_errors (breakpoint_cond_eval, b->cond,
+ "Error occurred in testing breakpoint condition.");
+ free_all_values ();
+ }
+ if (b->cond && value_zero)
+ {
+ cont = -1;
+ }
+ else if (b->ignore_count > 0)
+ {
+ b->ignore_count--;
+ cont = -1;
+ }
+ else
+ {
+ if (b->enable == temporary)
+ b->enable = disabled;
+ breakpoint_commands = b->commands;
+ if (b->silent
+ || (breakpoint_commands
+ && !strcmp ("silent", breakpoint_commands->line)))
+ {
+ if (breakpoint_commands)
+ breakpoint_commands = breakpoint_commands->next;
+ return (b->number > 0 ?
+ 0x1000000 + b->number :
+ b->number - 0x1000000);
+ }
+ return b->number;
+ }
+ }
+ }
+
+ return cont;
+}
+
+static void
+breakpoint_1 (bnum)
+ int bnum;
+{
+ register struct breakpoint *b;
+ register struct command_line *l;
+ register struct symbol *sym;
+ CORE_ADDR last_addr = (CORE_ADDR)-1;
+
+ ALL_BREAKPOINTS (b)
+ if (bnum == -1 || bnum == b->number)
+ {
+ printf_filtered ("#%-3d %c 0x%08x", b->number,
+ "nyod"[(int) b->enable],
+ b->address);
+ last_addr = b->address;
+ if (b->symtab)
+ {
+ sym = find_pc_function (b->address);
+ if (sym)
+ {
+ fputs_filtered (" in ", stdout);
+ fputs_demangled (SYMBOL_NAME (sym), stdout, 1);
+ fputs_filtered (" (", stdout);
+ }
+ fputs_filtered (b->symtab->filename, stdout);
+ printf_filtered (" line %d", b->line_number);
+ if (sym) fputs_filtered(")", stdout);
+ }
+ else
+ print_address_symbolic (b->address, stdout);
+
+ printf_filtered ("\n");
+
+ if (b->ignore_count)
+ printf_filtered ("\tignore next %d hits\n", b->ignore_count);
+ if (b->frame)
+ printf_filtered ("\tstop only in stack frame at 0x%x\n", b->frame);
+ if (b->cond)
+ {
+ printf_filtered ("\tbreak only if ");
+ print_expression (b->cond, stdout);
+ printf_filtered ("\n");
+ }
+ if (l = b->commands)
+ while (l)
+ {
+ printf_filtered ("\t%s\n", l->line);
+ l = l->next;
+ }
+ }
+
+ /* 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);
+}
+
+static void
+breakpoints_info (bnum_exp)
+ char *bnum_exp;
+{
+ int bnum = -1;
+
+ if (bnum_exp)
+ bnum = parse_and_eval_address (bnum_exp);
+ else if (breakpoint_chain == 0)
+ printf_filtered ("No breakpoints.\n");
+ else
+ printf_filtered ("Breakpoints:\n\
+Num Enb Address Where\n");
+
+ breakpoint_1 (bnum);
+}
+
+/* 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 ("Note: breakpoint%s ", (others > 1) ? "s" : "");
+ ALL_BREAKPOINTS (b)
+ if (b->address == pc)
+ {
+ others--;
+ printf ("%d%s%s ",
+ b->number,
+ (b->enable == disabled) ? " (disabled)" : "",
+ (others > 1) ? "," : ((others == 1) ? " and" : ""));
+ }
+ printf ("also set at pc 0x%x.\n", pc);
+ }
+}
+
+/* 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;
+
+ 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. */
+
+static struct breakpoint *
+set_raw_breakpoint (sal)
+ struct symtab_and_line sal;
+{
+ register struct breakpoint *b, *b1;
+
+ b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
+ bzero (b, sizeof *b);
+ b->address = sal.pc;
+ b->symtab = sal.symtab;
+ b->line_number = sal.line;
+ b->enable = enabled;
+ b->next = 0;
+ b->silent = 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);
+
+ return b;
+}
+
+/* Set a breakpoint that will evaporate an end of command
+ at address specified by SAL.
+ Restrict it to frame FRAME if FRAME is nonzero. */
+
+void
+set_momentary_breakpoint (sal, frame)
+ struct symtab_and_line sal;
+ FRAME frame;
+{
+ register struct breakpoint *b;
+ b = set_raw_breakpoint (sal);
+ b->number = -3;
+ b->enable = delete;
+ b->frame = (frame ? FRAME_FP (frame) : 0);
+}
+
+void
+clear_momentary_breakpoints ()
+{
+ register struct breakpoint *b;
+ ALL_BREAKPOINTS (b)
+ if (b->number == -3)
+ {
+ delete_breakpoint (b);
+ break;
+ }
+}
+
+/* Set a breakpoint from a symtab and line.
+ If TEMPFLAG is nonzero, it is a temporary breakpoint.
+ Print the same confirmation messages that the breakpoint command prints. */
+
+void
+set_breakpoint (s, line, tempflag)
+ struct symtab *s;
+ int line;
+ int tempflag;
+{
+ register struct breakpoint *b;
+ struct symtab_and_line sal;
+
+ sal.symtab = s;
+ sal.line = line;
+ sal.pc = find_line_pc (sal.symtab, sal.line);
+ if (sal.pc == 0)
+ error ("No line %d in file \"%s\".\n", sal.line, sal.symtab->filename);
+ else
+ {
+ describe_other_breakpoints (sal.pc);
+
+ b = set_raw_breakpoint (sal);
+ b->number = ++breakpoint_count;
+ b->cond = 0;
+ if (tempflag)
+ b->enable = temporary;
+
+ printf ("Breakpoint %d at 0x%x", b->number, b->address);
+ if (b->symtab)
+ printf (": file %s, line %d.", b->symtab->filename, b->line_number);
+ printf ("\n");
+ }
+}
+
+/* Set a breakpoint according to ARG (function, linenum or *address)
+ and make it temporary if TEMPFLAG is nonzero. */
+
+static void
+break_command_1 (arg, tempflag, from_tty)
+ char *arg;
+ int tempflag, from_tty;
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ register struct expression *cond = 0;
+ register struct breakpoint *b;
+ char *save_arg;
+ int i;
+ CORE_ADDR pc;
+
+ 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 *)
+ malloc (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
+ /* 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);
+ else
+ sals = decode_line_1 (&arg, 1, 0, 0);
+
+ if (! sals.nelts)
+ return;
+
+ save_arg = arg;
+ for (i = 0; i < sals.nelts; i++)
+ {
+ sal = sals.sals[i];
+ 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);
+ }
+ else
+ pc = sal.pc;
+
+ while (arg && *arg)
+ {
+ if (arg[0] == 'i' && arg[1] == 'f'
+ && (arg[2] == ' ' || arg[2] == '\t'))
+ cond = (struct expression *) parse_c_1 ((arg += 2, &arg),
+ block_for_pc (pc), 0);
+ else
+ error ("Junk at end of arguments.");
+ }
+ arg = save_arg;
+ sals.sals[i].pc = pc;
+ }
+
+ for (i = 0; i < sals.nelts; i++)
+ {
+ sal = sals.sals[i];
+
+ if (from_tty)
+ describe_other_breakpoints (sal.pc);
+
+ b = set_raw_breakpoint (sal);
+ b->number = ++breakpoint_count;
+ b->cond = cond;
+ if (tempflag)
+ b->enable = temporary;
+
+ printf ("Breakpoint %d at 0x%x", b->number, b->address);
+ if (b->symtab)
+ printf (": file %s, line %d.", b->symtab->filename, b->line_number);
+ printf ("\n");
+ }
+
+ if (sals.nelts > 1)
+ {
+ printf ("Multiple breakpoints were set.\n");
+ printf ("Use the \"delete\" command to delete unwanted breakpoints.\n");
+ }
+ free (sals.sals);
+}
+
+static 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, 1, from_tty);
+}
+
+/*
+ * Helper routine for the until_command routine in infcmd.c. Here
+ * because it uses the mechanisms of breakpoints.
+ */
+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);
+
+ 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);
+ else
+ sals = decode_line_1 (&arg, 1, 0, 0);
+
+ if (sals.nelts != 1)
+ error ("Couldn't get information on specified line.");
+
+ sal = sals.sals[0];
+ free (sals.sals); /* malloc'd, so freed */
+
+ if (*arg)
+ error ("Junk at end of arguments.");
+
+ if (sal.pc == 0 && sal.symtab != 0)
+ sal.pc = find_line_pc (sal.symtab, sal.line);
+
+ if (sal.pc == 0)
+ error ("No line %d in file \"%s\".", sal.line, sal.symtab->filename);
+
+ set_momentary_breakpoint (sal, selected_frame);
+
+ /* 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;
+ set_momentary_breakpoint (sal, prev_frame);
+ }
+
+ proceed (-1, -1, 0);
+}
+
+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 *) malloc (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->symtab == sal.symtab
+ && breakpoint_chain->line_number == sal.line)))
+ {
+ b1 = breakpoint_chain;
+ breakpoint_chain = b1->next;
+ b1->next = found;
+ found = b1;
+ }
+
+ ALL_BREAKPOINTS (b)
+ while (b->next
+ && (sal.pc ? b->next->address == sal.pc
+ : (b->next->symtab == sal.symtab
+ && b->next->line_number == sal.line)))
+ {
+ b1 = b->next;
+ b->next = b1->next;
+ b1->next = found;
+ found = b1;
+ }
+
+ if (found == 0)
+ error ("No breakpoint at %s.", arg);
+
+ if (found->next) from_tty = 1; /* Always report if deleted more than one */
+ if (from_tty) printf ("Deleted breakpoint%s ", found->next ? "s" : "");
+ while (found)
+ {
+ if (from_tty) printf ("%d ", found->number);
+ b1 = found->next;
+ delete_breakpoint (found);
+ found = b1;
+ }
+ if (from_tty) putchar ('\n');
+ }
+ free (sals.sals);
+}
+
+/* Delete breakpoint number BNUM if it is a `delete' breakpoint.
+ This is called after breakpoint BNUM has been hit.
+ Also delete any breakpoint numbered -3 unless there are breakpoint
+ commands to be executed. */
+
+void
+breakpoint_auto_delete (bnum)
+ int bnum;
+{
+ register struct breakpoint *b;
+ if (bnum != 0)
+ ALL_BREAKPOINTS (b)
+ if (b->number == bnum)
+ {
+ if (b->enable == delete)
+ delete_breakpoint (b);
+ break;
+ }
+ if (breakpoint_commands == 0)
+ clear_momentary_breakpoints ();
+}
+
+static void
+delete_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ register struct breakpoint *b;
+
+ if (bpt->inserted)
+ write_memory (bpt->address, bpt->shadow_contents, sizeof break_insn);
+
+ if (breakpoint_chain == bpt)
+ breakpoint_chain = bpt->next;
+
+ ALL_BREAKPOINTS (b)
+ if (b->next == bpt)
+ {
+ b->next = bpt->next;
+ break;
+ }
+
+ check_duplicates (bpt->address);
+
+ free_command_lines (bpt->commands);
+ if (bpt->cond)
+ free (bpt->cond);
+
+ if (xgdb_verbose && bpt->number >=0)
+ printf ("breakpoint #%d deleted\n", bpt->number);
+
+ free (bpt);
+}
+
+static void map_breakpoint_numbers ();
+
+static void
+delete_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register struct breakpoint *b, *b1;
+
+ if (arg == 0)
+ {
+ /* Ask user only if there are some breakpoints to delete. */
+ if (!from_tty
+ || breakpoint_chain && query ("Delete all breakpoints? "))
+ {
+ /* No arg; clear all breakpoints. */
+ while (breakpoint_chain)
+ delete_breakpoint (breakpoint_chain);
+ }
+ }
+ else
+ map_breakpoint_numbers (arg, delete_breakpoint);
+}
+
+/* Delete all breakpoints.
+ Done when new symtabs are loaded, since the break condition expressions
+ may become invalid, and the breakpoints are probably wrong anyway. */
+
+void
+clear_breakpoints ()
+{
+ delete_command (0, 0);
+}
+
+/* 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 ("Will stop next time breakpoint %d is reached.", bptnum);
+ else if (count == 1)
+ printf ("Will ignore next crossing of breakpoint %d.", bptnum);
+ else
+ printf ("Will ignore next %d crossings of breakpoint %d.",
+ count, bptnum);
+ 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;
+{
+ register char *p = args;
+ register int num;
+
+ if (p == 0)
+ error_no_arg ("a breakpoint number");
+
+ while (*p >= '0' && *p <= '9') p++;
+ if (*p && *p != ' ' && *p != '\t')
+ error ("First argument must be a breakpoint number.");
+
+ num = atoi (args);
+
+ if (*p == 0)
+ error ("Second argument (specified ignore-count) is missing.");
+
+ set_ignore_count (num, parse_and_eval_address (p), from_tty);
+ printf ("\n");
+}
+
+/* Call FUNCTION on each of the breakpoints
+ whose numbers are given in ARGS. */
+
+static void
+map_breakpoint_numbers (args, function)
+ char *args;
+ void (*function) ();
+{
+ register char *p = args;
+ register char *p1;
+ register int num;
+ register struct breakpoint *b;
+
+ if (p == 0)
+ error_no_arg ("one or more breakpoint numbers");
+
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9') p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be breakpoint numbers.");
+
+ num = atoi (p);
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == num)
+ {
+ function (b);
+ goto win;
+ }
+ printf ("No breakpoint number %d.\n", num);
+ win:
+ p = p1;
+ while (*p == ' ' || *p == '\t') p++;
+ }
+}
+
+static void
+enable_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ bpt->enable = enabled;
+
+ if (xgdb_verbose && bpt->number >= 0)
+ printf ("breakpoint #%d enabled\n", bpt->number);
+
+ check_duplicates (bpt->address);
+}
+
+static void
+enable_command (args)
+ char *args;
+{
+ struct breakpoint *bpt;
+ if (args == 0)
+ ALL_BREAKPOINTS (bpt)
+ enable_breakpoint (bpt);
+ else
+ map_breakpoint_numbers (args, enable_breakpoint);
+}
+
+static void
+disable_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ bpt->enable = disabled;
+
+ if (xgdb_verbose && bpt->number >= 0)
+ printf ("breakpoint #%d disabled\n", bpt->number);
+
+ check_duplicates (bpt->address);
+}
+
+static void
+disable_command (args)
+ char *args;
+{
+ register struct breakpoint *bpt;
+ if (args == 0)
+ ALL_BREAKPOINTS (bpt)
+ disable_breakpoint (bpt);
+ else
+ map_breakpoint_numbers (args, disable_breakpoint);
+}
+
+static void
+enable_once_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ bpt->enable = temporary;
+
+ check_duplicates (bpt->address);
+}
+
+static void
+enable_once_command (args)
+ char *args;
+{
+ map_breakpoint_numbers (args, enable_once_breakpoint);
+}
+
+static void
+enable_delete_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ bpt->enable = delete;
+
+ check_duplicates (bpt->address);
+}
+
+static void
+enable_delete_command (args)
+ char *args;
+{
+ 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);
+ else
+ sals = decode_line_1 (&string, funfirstline, 0, 0);
+ if (*string)
+ error ("Junk at end of line specification: %s", string);
+ return sals;
+}
+
+
+/* Chain containing all defined enable commands. */
+
+extern struct cmd_list_element
+ *enablelist, *disablelist,
+ *deletelist, *enablebreaklist;
+
+extern struct cmd_list_element *cmdlist;
+
+void
+_initialize_breakpoint ()
+{
+ breakpoint_chain = 0;
+ breakpoint_count = 0;
+
+ add_com ("ignore", class_breakpoint, ignore_command,
+ "Set ignore-count of breakpoint number N to 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\
+N is an integer; COND is a C expression to be evaluated whenever\n\
+breakpoint N is reached. Actually break only when COND is nonzero.");
+
+ add_com ("tbreak", class_breakpoint, tbreak_command,
+ "Set a temporary breakpoint. Args like \"break\" command.\n\
+Like \"break\" except the breakpoint is only enabled temporarily,\n\
+so it will be disabled when hit. Equivalent to \"break\" followed\n\
+by using \"enable once\" on the breakpoint number.");
+
+ add_prefix_cmd ("enable", class_breakpoint, enable_command,
+ "Enable some breakpoints or auto-display expressions.\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.\n\
+\n\
+The \"display\" subcommand applies to auto-displays instead of breakpoints.",
+ &enablelist, "enable ", 1, &cmdlist);
+
+ add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command,
+ "Enable some breakpoints or auto-display expressions.\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\
+May be abbreviates to simply \"enable\".\n\
+With a subcommand you can enable temporarily.",
+ &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.\n\
+See the \"tbreak\" command which sets a breakpoint and enables it once.",
+ &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.\n\
+See the \"tbreak\" command which sets a breakpoint and enables it once.",
+ &enablelist);
+
+ add_prefix_cmd ("disable", class_breakpoint, disable_command,
+ "Disable some breakpoints or auto-display expressions.\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\
+\n\
+The \"display\" subcommand applies to auto-displays instead of breakpoints.",
+ &disablelist, "disable ", 1, &cmdlist);
+ add_com_alias ("dis", "disable", class_breakpoint, 1);
+ add_com_alias ("disa", "disable", class_breakpoint, 1);
+
+ add_abbrev_cmd ("breakpoints", class_breakpoint, disable_command,
+ "Disable some breakpoints or auto-display expressions.\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_com_alias ("unset", "delete", class_alias, 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 all breakpoints, or breakpoint number NUMBER.\n\
+Second column is \"y\" for enabled breakpoint, \"n\" for disabled,\n\
+\"o\" for enabled once (disable when hit), \"d\" for enable but delete when hit.\n\
+Then come the address and the file/line number.\n\n\
+Convenience variable \"$_\" and default examine address for \"x\"\n\
+are set to the address of the last breakpoint listed.");
+}
+
diff --git a/gnu/usr.bin/gdb/command.c b/gnu/usr.bin/gdb/command.c
new file mode 100644
index 0000000..79daea4
--- /dev/null
+++ b/gnu/usr.bin/gdb/command.c
@@ -0,0 +1,856 @@
+/* Library for reading command lines and decoding commands.
+ 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 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. */
+
+#include "command.h"
+#include "defs.h"
+#include <stdio.h>
+#include <ctype.h>
+
+extern char *xmalloc ();
+
+/* Add element named NAME to command list *LIST.
+ 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. */
+
+struct cmd_list_element *
+add_cmd (name, class, fun, doc, list)
+ char *name;
+ int class;
+ void (*fun) ();
+ 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 = savestring (name, strlen (name));
+ c->class = class;
+ c->function = fun;
+ c->doc = doc;
+ c->prefixlist = 0;
+ c->allow_unknown = 0;
+ c->abbrev_flag = 0;
+ c->aux = 0;
+ *list = c;
+ return c;
+}
+
+/* Same as above, except that the abbrev_flag is set. */
+
+struct cmd_list_element *
+add_abbrev_cmd (name, class, fun, doc, list)
+ char *name;
+ int class;
+ void (*fun) ();
+ 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 = savestring (name, strlen (name));
+ c->class = class;
+ c->function = fun;
+ c->doc = doc;
+ c->prefixlist = 0;
+ c->allow_unknown = 0;
+ c->abbrev_flag = 1;
+ c->aux = 0;
+ *list = c;
+ return c;
+}
+
+struct cmd_list_element *
+add_alias_cmd (name, oldname, class, abbrev_flag, list)
+ char *name;
+ char *oldname;
+ int 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, 0, 1, 1);
+
+ if (old == 0)
+ {
+ delete_cmd (name, list);
+ return 0;
+ }
+
+ c = add_cmd (name, class, old->function, old->doc, list);
+ c->prefixlist = old->prefixlist;
+ c->prefixname = old->prefixname;
+ c->allow_unknown = old->allow_unknown;
+ c->abbrev_flag = abbrev_flag;
+ c->aux = old->aux;
+ 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;
+ int class;
+ void (*fun) ();
+ 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 butsets 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;
+ int class;
+ void (*fun) ();
+ 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;
+}
+
+/* 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;
+
+ while (*list && !strcmp ((*list)->name, name))
+ {
+ *list = (*list)->next;
+ }
+
+ if (*list)
+ for (c = *list; c->next;)
+ {
+ if (!strcmp (c->next->name, name))
+ c->next = c->next->next;
+ else
+ c = c->next;
+ }
+}
+
+void help_cmd (), help_list (), help_cmd_list ();
+
+/* 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;
+ FILE *stream;
+{
+ struct cmd_list_element *c;
+ extern struct cmd_list_element *cmdlist;
+
+ if (!command)
+ {
+ help_list (cmdlist, "", -2, stream);
+ return;
+ }
+
+ c = lookup_cmd (&command, cmdlist, "", 0, 0);
+
+ if (c == 0)
+ return;
+
+ /* There are three cases here.
+ If c->prefixlist is nonzer, 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 he 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 != 0)
+ return;
+ fprintf_filtered (stream, "\n");
+
+ /* If this is a prefix command, print it's subcommands */
+ if (c->prefixlist)
+ help_list (*c->prefixlist, c->prefixname, -1, stream);
+
+ /* If this is a class name, print all of the commands in the class */
+ if (c->function == 0)
+ help_list (cmdlist, "", c->class, stream);
+}
+
+/*
+ * 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, -1 for
+ * everything, -2 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;
+ int class;
+ 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 == -2)
+ 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, (class >= 0), stream);
+
+ if (class == -2)
+ 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);
+}
+
+
+/*
+ * 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.
+ * -1 to list all commands in list.
+ * -2 to list all classes in list.
+ *
+ * Note that RECURSE will be active on *all* sublists, not just the
+ * ones seclected 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;
+ int class;
+ char *prefix;
+ int recurse;
+ FILE *stream;
+{
+ register struct cmd_list_element *c;
+ register char *p;
+ static char *line_buffer = 0;
+ static int line_size;
+
+ if (!line_buffer)
+ {
+ line_size = 80;
+ line_buffer = (char *) xmalloc (line_size);
+ }
+
+ for (c = list; c; c = c->next)
+ {
+ if (c->abbrev_flag == 0 &&
+ (class == -1
+ || (class == -2 && c->function == 0)
+ || (class == c->class && c->function != 0)))
+ {
+ fprintf_filtered (stream, "%s%s -- ", prefix, c->name);
+ /* Print just the first line */
+ p = c->doc;
+ while (*p && *p != '\n') p++;
+ if (p - c->doc > line_size - 1)
+ {
+ line_size = p - c->doc + 1;
+ free (line_buffer);
+ line_buffer = (char *) xmalloc (line_size);
+ }
+ strncpy (line_buffer, c->doc, p - c->doc);
+ line_buffer[p - c->doc] = '\0';
+ fputs_filtered (line_buffer, stream);
+ 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
+ the list in which the last word was matched, and will return the
+ cmd list element which the text matches. It will return 0 if no
+ match at all was possible. It will return -1 if ambigous matches are
+ possible; in this case *RESULT_LIST will be set to the list in which
+ there are ambiguous choices (and text will be set to the ambiguous
+ text string).
+
+ 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 0 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.
+
+ This routine does *not* modify the text pointed to by TEXT.
+
+ 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_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] = (x >= 'A' && x <= 'Z') ? x - 'A' + 'a' : 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))
+ {
+ 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)
+ {
+ *result_list = 0; /* Will be modified in calling routine
+ if we know what the prefix command is.
+ */
+ return (struct cmd_list_element *) -1; /* Ambiguous. */
+ }
+
+ /* We've matched something on this list. Move text pointer forward. */
+
+ *text = p;
+ 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. */
+ *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)
+ /* 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
+ {
+ *result_list = clist;
+ return found;
+ }
+}
+
+/* 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);
+ char *ptr = (*line) + strlen (*line) - 1;
+
+ /* Clear off trailing whitespace. */
+ while (ptr >= *line && (*ptr == ' ' || *ptr == '\t'))
+ ptr--;
+ *(ptr + 1) = '\0';
+
+ 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';
+
+ error ("Undefined %scommand: \"%s\".", 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 < sizeof ambbuf)
+ {
+ if (strlen (ambbuf))
+ strcat (ambbuf, ", ");
+ strcat (ambbuf, c->name);
+ }
+ else
+ {
+ strcat (ambbuf, "..");
+ break;
+ }
+ }
+ error ("Ambiguous %scommand \"%s\": %s.", local_cmdtype,
+ *line, ambbuf);
+ }
+ }
+ 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)
+ error ("Undefined %scommand: \"%s\".", c->prefixname, *line);
+
+ /* Seems to be what he wants. Return it. */
+ return c;
+ }
+}
+
+#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 == '-'
+ || (*p >= 'a' && *p <= 'z')
+ || (*p >= 'A' && *p <= 'Z')
+ || (*p >= '0' && *p <= '9'))
+ 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 (x >= 'A' && x <= 'Z')
+ processed_cmd[cmd_len] = x - 'A' + 'a';
+ 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. */
+
+char **
+complete_on_cmdlist (list, text)
+ struct cmd_list_element *list;
+ char *text;
+{
+ 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
+ || ptr->prefixlist))
+ {
+ if (matches == sizeof_matchlist)
+ {
+ sizeof_matchlist *= 2;
+ matchlist = (char **) xrealloc (matchlist,
+ (sizeof_matchlist
+ * sizeof (char *)));
+ }
+
+ matchlist[matches] = (char *)
+ xmalloc (strlen (ptr->name) + 1);
+ strcpy (matchlist[matches++], ptr->name);
+ }
+
+ if (matches == 0)
+ {
+ free (matchlist);
+ matchlist = 0;
+ }
+ else
+ {
+ matchlist = (char **) xrealloc (matchlist, ((matches + 1)
+ * sizeof (char *)));
+ matchlist[matches] = (char *) 0;
+ }
+
+ return matchlist;
+}
+
+static void
+shell_escape (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ int rc, status, pid;
+ char *p, *user_shell;
+ extern char *rindex ();
+
+ if ((user_shell = (char *) getenv ("SHELL")) == NULL)
+ user_shell = "/bin/sh";
+
+ /* Get the name of the shell for arg0 */
+ if ((p = rindex (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 (stderr, "Exec of shell failed\n");
+ exit (0);
+ }
+
+ if (pid != -1)
+ while ((rc = wait (&status)) != pid && rc != -1)
+ ;
+ else
+ error ("Fork failed");
+}
+
+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.");
+}
diff --git a/gnu/usr.bin/gdb/command.h b/gnu/usr.bin/gdb/command.h
new file mode 100644
index 0000000..fe28aef
--- /dev/null
+++ b/gnu/usr.bin/gdb/command.h
@@ -0,0 +1,77 @@
+/* Header file for command-reading library command.c.
+ 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 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 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. */
+ int class;
+
+ /* Function definition of this command.
+ Zero for command class names and for help topics that
+ are not really commands. */
+ void (*function) ();
+
+ /* 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;
+
+ /* Auxiliary information.
+ It is up to the calling program to decide what this means. */
+ char *aux;
+
+ /* 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;
+ };
+
+/* Forward-declarations of the entry-points of command.c. */
+
+extern struct cmd_list_element *add_cmd ();
+extern struct cmd_list_element *add_alias_cmd ();
+extern struct cmd_list_element *add_prefix_cmd ();
+extern struct cmd_list_element *lookup_cmd (), *lookup_cmd_1 ();
+extern char **complete_on_cmdlist ();
+extern void delete_cmd ();
+extern void help_cmd ();
diff --git a/gnu/usr.bin/gdb/config/Makefile.i386 b/gnu/usr.bin/gdb/config/Makefile.i386
new file mode 100644
index 0000000..cc52aa3
--- /dev/null
+++ b/gnu/usr.bin/gdb/config/Makefile.i386
@@ -0,0 +1,6 @@
+# @(#)Makefile.i386 6.2 (Berkeley) 3/21/91
+
+CONFIGSRCS= i386bsd-dep.c i386-pinsn.c
+
+param.h:
+ ln -s $(.CURDIR)/config/m-i386bsd.h param.h
diff --git a/gnu/usr.bin/gdb/config/default-dep.c b/gnu/usr.bin/gdb/config/default-dep.c
new file mode 100644
index 0000000..13fe7b9
--- /dev/null
+++ b/gnu/usr.bin/gdb/config/default-dep.c
@@ -0,0 +1,585 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)default-dep.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Low level interface to ptrace, for GDB when running under Unix.
+ Copyright (C) 1988, 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. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+/* #include <fcntl.h> Can we live without this? */
+
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#else
+#include <a.out.h>
+#endif
+#ifndef N_SET_MAGIC
+#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
+#endif
+
+#include <sys/user.h> /* After a.out.h */
+#include <sys/file.h>
+#include <sys/stat.h>
+
+extern int errno;
+
+/* 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, arg3, arg4)
+ int request, pid, arg3, arg4;
+{
+ return ptrace (request, pid, arg3, arg4);
+}
+
+kill_inferior ()
+{
+ if (remote_debugging)
+ return;
+ if (inferior_pid == 0)
+ return;
+ ptrace (8, inferior_pid, 0, 0);
+ wait (0);
+ inferior_died ();
+}
+
+/* This is used when GDB is exiting. It gives less chance of error.*/
+
+kill_inferior_fast ()
+{
+ if (remote_debugging)
+ return;
+ if (inferior_pid == 0)
+ return;
+ ptrace (8, inferior_pid, 0, 0);
+ wait (0);
+}
+
+/* Resume execution of the inferior process.
+ If STEP is nonzero, single-step it.
+ If SIGNAL is nonzero, give it that signal. */
+
+void
+resume (step, signal)
+ int step;
+ int signal;
+{
+ errno = 0;
+ if (remote_debugging)
+ remote_resume (step, signal);
+ else
+ {
+ ptrace (step ? 9 : 7, inferior_pid, 1, signal);
+ if (errno)
+ perror_with_name ("ptrace");
+ }
+}
+
+void
+fetch_inferior_registers ()
+{
+ register int regno;
+ register unsigned int regaddr;
+ char buf[MAX_REGISTER_RAW_SIZE];
+ register int i;
+
+ struct user u;
+ unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
+ offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ regaddr = register_addr (regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
+ {
+ *(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0);
+ regaddr += sizeof (int);
+ }
+ supply_register (regno, buf);
+ }
+}
+
+/* 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). */
+
+store_inferior_registers (regno)
+ int regno;
+{
+ register unsigned int regaddr;
+ char buf[80];
+
+ struct user u;
+ unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
+ offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
+
+ if (regno >= 0)
+ {
+ regaddr = register_addr (regno, offset);
+ errno = 0;
+ ptrace (6, inferior_pid, regaddr, read_register (regno));
+ if (errno != 0)
+ {
+ sprintf (buf, "writing register number %d", regno);
+ perror_with_name (buf);
+ }
+ }
+ else for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ regaddr = register_addr (regno, offset);
+ errno = 0;
+ ptrace (6, inferior_pid, regaddr, read_register (regno));
+ if (errno != 0)
+ {
+ sprintf (buf, "writing all regs, number %d", regno);
+ perror_with_name (buf);
+ }
+ }
+}
+
+/* Copy LEN bytes from inferior's memory starting at MEMADDR
+ to debugger memory starting at MYADDR.
+ On failure (cannot read from inferior, usually because address is out
+ of bounds) returns the value of errno. */
+
+int
+read_inferior_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & - sizeof (int);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count
+ = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
+ /* Allocate buffer of that many longwords. */
+ register int *buffer = (int *) alloca (count * sizeof (int));
+ extern int errno;
+
+ /* Read all the longwords */
+ for (i = 0; i < count; i++, addr += sizeof (int))
+ {
+ errno = 0;
+#if 0
+ /* This is now done by read_memory, because when this function did it,
+ reading a byte or short int hardware port read whole longs, causing
+ serious side effects
+ such as bus errors and unexpected hardware operation. This would
+ also be a problem with ptrace if the inferior process could read
+ or write hardware registers, but that's not usually the case. */
+ if (remote_debugging)
+ buffer[i] = remote_fetch_word (addr);
+ else
+#endif
+ buffer[i] = ptrace (1, inferior_pid, addr, 0);
+ if (errno)
+ return errno;
+ }
+
+ /* Copy appropriate bytes out of the buffer. */
+ bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
+ return 0;
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR
+ to inferior's memory at MEMADDR.
+ On failure (cannot write the inferior)
+ returns the value of errno. */
+
+int
+write_inferior_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & - sizeof (int);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count
+ = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
+ /* Allocate buffer of that many longwords. */
+ register int *buffer = (int *) alloca (count * sizeof (int));
+ extern int errno;
+
+ /* Fill start and end extra bytes of buffer with existing memory data. */
+
+ if (remote_debugging)
+ return (remote_write_inferior_memory(memaddr, myaddr, len));
+
+ buffer[0] = ptrace (1, inferior_pid, addr, 0);
+
+ if (count > 1)
+ buffer[count - 1] = ptrace (1, inferior_pid,
+ addr + (count - 1) * sizeof (int), 0);
+
+ /* Copy data to be written over corresponding part of buffer */
+
+ bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
+
+ /* Write the entire buffer. */
+
+ for (i = 0; i < count; i++, addr += sizeof (int))
+ {
+ errno = 0;
+ ptrace (4, inferior_pid, addr, buffer[i]);
+ if (errno)
+ return errno;
+ }
+
+ return 0;
+}
+
+/* Work with core dump and executable files, for GDB.
+ This code would be in core.c if it weren't machine-dependent. */
+
+#ifndef N_TXTADDR
+#define N_TXTADDR(hdr) 0
+#endif /* no N_TXTADDR */
+
+#ifndef N_DATADDR
+#define N_DATADDR(hdr) hdr.a_text
+#endif /* no N_DATADDR */
+
+/* Make COFF and non-COFF names for things a little more compatible
+ to reduce conditionals later. */
+
+#ifdef COFF_FORMAT
+#define a_magic magic
+#endif
+
+#ifndef COFF_FORMAT
+#ifndef AOUTHDR
+#define AOUTHDR struct exec
+#endif
+#endif
+
+extern char *sys_siglist[];
+
+
+/* Hook for `exec_file_command' command to call. */
+
+extern void (*exec_file_display_hook) ();
+
+/* File names of core file and executable file. */
+
+extern char *corefile;
+extern char *execfile;
+
+/* Descriptors on which core file and executable file are open.
+ Note that the execchan is closed when an inferior is created
+ and reopened if the inferior dies or is killed. */
+
+extern int corechan;
+extern int execchan;
+
+/* Last modification time of executable file.
+ Also used in source.c to compare against mtime of a source file. */
+
+extern int exec_mtime;
+
+/* Virtual addresses of bounds of the two areas of memory in the core file. */
+
+extern CORE_ADDR data_start;
+extern CORE_ADDR data_end;
+extern CORE_ADDR stack_start;
+extern CORE_ADDR stack_end;
+
+/* Virtual addresses of bounds of two areas of memory in the exec file.
+ Note that the data area in the exec file is used only when there is no core file. */
+
+extern CORE_ADDR text_start;
+extern CORE_ADDR text_end;
+
+extern CORE_ADDR exec_data_start;
+extern CORE_ADDR exec_data_end;
+
+/* Address in executable file of start of text area data. */
+
+extern int text_offset;
+
+/* Address in executable file of start of data area data. */
+
+extern int exec_data_offset;
+
+/* Address in core file of start of data area data. */
+
+extern int data_offset;
+
+/* Address in core file of start of stack area data. */
+
+extern int stack_offset;
+
+#ifdef COFF_FORMAT
+/* various coff data structures */
+
+extern FILHDR file_hdr;
+extern SCNHDR text_hdr;
+extern SCNHDR data_hdr;
+
+#endif /* not COFF_FORMAT */
+
+/* a.out header saved in core file. */
+
+extern AOUTHDR core_aouthdr;
+
+/* a.out header of exec file. */
+
+extern AOUTHDR exec_aouthdr;
+
+extern void validate_files ();
+
+core_file_command (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ int val;
+ extern char registers[];
+
+ /* Discard all vestiges of any previous core file
+ and mark data and stack spaces as empty. */
+
+ if (corefile)
+ free (corefile);
+ corefile = 0;
+
+ if (corechan >= 0)
+ close (corechan);
+ corechan = -1;
+
+ data_start = 0;
+ data_end = 0;
+ stack_start = STACK_END_ADDR;
+ stack_end = STACK_END_ADDR;
+
+ /* Now, if a new core file was specified, open it and digest it. */
+
+ if (filename)
+ {
+ filename = tilde_expand (filename);
+ make_cleanup (free, filename);
+
+ if (have_inferior_p ())
+ error ("To look at a core file, you must kill the inferior with \"kill\".");
+ corechan = open (filename, O_RDONLY, 0);
+ if (corechan < 0)
+ perror_with_name (filename);
+ /* 4.2-style (and perhaps also sysV-style) core dump file. */
+ {
+ struct user u;
+
+ unsigned int reg_offset;
+
+ val = myread (corechan, &u, sizeof u);
+ if (val < 0)
+ perror_with_name ("Not a core file: reading upage");
+ if (val != sizeof u)
+ error ("Not a core file: could only read %d bytes", val);
+
+ /* We are depending on exec_file_command having been called
+ previously to set exec_data_start. Since the executable
+ and the core file share the same text segment, the address
+ of the data segment will be the same in both. */
+ data_start = exec_data_start;
+
+ data_end = data_start + NBPG * u.u_dsize;
+ stack_start = stack_end - NBPG * u.u_ssize;
+ data_offset = NBPG * UPAGES;
+ stack_offset = NBPG * (UPAGES + u.u_dsize);
+
+ /* Some machines put an absolute address in here and some put
+ the offset in the upage of the regs. */
+ reg_offset = (int) u.u_ar0;
+ if (reg_offset > NBPG * UPAGES)
+ reg_offset -= KERNEL_U_ADDR;
+
+ /* I don't know where to find this info.
+ So, for now, mark it as not available. */
+ N_SET_MAGIC (core_aouthdr, 0);
+
+ /* Read the register values out of the core file and store
+ them where `read_register' will find them. */
+
+ {
+ register int regno;
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ char buf[MAX_REGISTER_RAW_SIZE];
+
+ val = lseek (corechan, register_addr (regno, reg_offset), 0);
+ if (val < 0
+ || (val = myread (corechan, buf, sizeof buf)) < 0)
+ {
+ char * buffer = (char *) alloca (strlen (reg_names[regno])
+ + 30);
+ strcpy (buffer, "Reading register ");
+ strcat (buffer, reg_names[regno]);
+
+ perror_with_name (buffer);
+ }
+
+ supply_register (regno, buf);
+ }
+ }
+ }
+ if (filename[0] == '/')
+ corefile = savestring (filename, strlen (filename));
+ else
+ {
+ corefile = concat (current_directory, "/", filename);
+ }
+
+ set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+ select_frame (get_current_frame (), 0);
+ validate_files ();
+ }
+ else if (from_tty)
+ printf ("No core file now.\n");
+}
+
+exec_file_command (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ int val;
+
+ /* Eliminate all traces of old exec file.
+ Mark text segment as empty. */
+
+ if (execfile)
+ free (execfile);
+ execfile = 0;
+ data_start = 0;
+ data_end -= exec_data_start;
+ text_start = 0;
+ text_end = 0;
+ exec_data_start = 0;
+ exec_data_end = 0;
+ if (execchan >= 0)
+ close (execchan);
+ execchan = -1;
+
+ /* Now open and digest the file the user requested, if any. */
+
+ if (filename)
+ {
+ filename = tilde_expand (filename);
+ make_cleanup (free, filename);
+
+ execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
+ &execfile);
+ if (execchan < 0)
+ perror_with_name (filename);
+
+#ifdef COFF_FORMAT
+ {
+ int aout_hdrsize;
+ int num_sections;
+
+ if (read_file_hdr (execchan, &file_hdr) < 0)
+ error ("\"%s\": not in executable format.", execfile);
+
+ aout_hdrsize = file_hdr.f_opthdr;
+ num_sections = file_hdr.f_nscns;
+
+ if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0)
+ error ("\"%s\": can't read optional aouthdr", execfile);
+
+ if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections,
+ aout_hdrsize) < 0)
+ error ("\"%s\": can't read text section header", execfile);
+
+ if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections,
+ aout_hdrsize) < 0)
+ error ("\"%s\": can't read data section header", execfile);
+
+ text_start = exec_aouthdr.text_start;
+ text_end = text_start + exec_aouthdr.tsize;
+ text_offset = text_hdr.s_scnptr;
+ exec_data_start = exec_aouthdr.data_start;
+ exec_data_end = exec_data_start + exec_aouthdr.dsize;
+ exec_data_offset = data_hdr.s_scnptr;
+ data_start = exec_data_start;
+ data_end += exec_data_start;
+ exec_mtime = file_hdr.f_timdat;
+ }
+#else /* not COFF_FORMAT */
+ {
+ struct stat st_exec;
+
+#ifdef HEADER_SEEK_FD
+ HEADER_SEEK_FD (execchan);
+#endif
+
+ val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
+
+ if (val < 0)
+ perror_with_name (filename);
+
+ text_start = N_TXTADDR (exec_aouthdr);
+ exec_data_start = N_DATADDR (exec_aouthdr);
+
+ text_offset = N_TXTOFF (exec_aouthdr);
+ exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
+
+ text_end = text_start + exec_aouthdr.a_text;
+ exec_data_end = exec_data_start + exec_aouthdr.a_data;
+ data_start = exec_data_start;
+ data_end += exec_data_start;
+
+ if (fstat (execchan, &st_exec) < 0)
+ perror_with_name (filename);
+ exec_mtime = st_exec.st_mtime;
+ }
+#endif /* not COFF_FORMAT */
+
+ validate_files ();
+ }
+ else if (from_tty)
+ printf ("No exec file now.\n");
+
+ /* Tell display code (if any) about the changed file name. */
+ if (exec_file_display_hook)
+ (*exec_file_display_hook) (filename);
+}
diff --git a/gnu/usr.bin/gdb/config/i386-dep.c b/gnu/usr.bin/gdb/config/i386-dep.c
new file mode 100644
index 0000000..c4630d0
--- /dev/null
+++ b/gnu/usr.bin/gdb/config/i386-dep.c
@@ -0,0 +1,1275 @@
+/* Low level interface to ptrace, for GDB when running on the Intel 386.
+ Copyright (C) 1988, 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. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/user.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#else
+#include <a.out.h>
+#endif
+
+#ifndef N_SET_MAGIC
+#ifdef COFF_FORMAT
+#define N_SET_MAGIC(exec, val) ((exec).magic = (val))
+#else
+#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
+#endif
+#endif
+
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include <sys/reg.h>
+
+extern int errno;
+
+/* 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, arg3, arg4)
+ int request, pid, arg3, arg4;
+{
+ return ptrace (request, pid, arg3, arg4);
+}
+
+kill_inferior ()
+{
+ if (remote_debugging)
+ return;
+ if (inferior_pid == 0)
+ return;
+ ptrace (8, inferior_pid, 0, 0);
+ wait (0);
+ inferior_died ();
+}
+
+/* This is used when GDB is exiting. It gives less chance of error.*/
+
+kill_inferior_fast ()
+{
+ if (remote_debugging)
+ return;
+ if (inferior_pid == 0)
+ return;
+ ptrace (8, inferior_pid, 0, 0);
+ wait (0);
+}
+
+/* Resume execution of the inferior process.
+ If STEP is nonzero, single-step it.
+ If SIGNAL is nonzero, give it that signal. */
+
+void
+resume (step, signal)
+ int step;
+ int signal;
+{
+ errno = 0;
+ if (remote_debugging)
+ remote_resume (step, signal);
+ else
+ {
+ ptrace (step ? 9 : 7, inferior_pid, 1, signal);
+ if (errno)
+ perror_with_name ("ptrace");
+ }
+}
+
+void
+fetch_inferior_registers ()
+{
+ register int regno;
+ register unsigned int regaddr;
+ char buf[MAX_REGISTER_RAW_SIZE];
+ register int i;
+
+ struct user u;
+ unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
+ offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ regaddr = register_addr (regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
+ {
+ *(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0);
+ regaddr += sizeof (int);
+ }
+ supply_register (regno, buf);
+ }
+}
+
+/* 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). */
+
+store_inferior_registers (regno)
+ int regno;
+{
+ register unsigned int regaddr;
+ char buf[80];
+
+ struct user u;
+ unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
+ offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
+
+ if (regno >= 0)
+ {
+ regaddr = register_addr (regno, offset);
+ errno = 0;
+ ptrace (6, inferior_pid, regaddr, read_register (regno));
+ if (errno != 0)
+ {
+ sprintf (buf, "writing register number %d", regno);
+ perror_with_name (buf);
+ }
+ }
+ else for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ regaddr = register_addr (regno, offset);
+ errno = 0;
+ ptrace (6, inferior_pid, regaddr, read_register (regno));
+ if (errno != 0)
+ {
+ sprintf (buf, "writing register number %d", regno);
+ perror_with_name (buf);
+ }
+ }
+}
+
+/* Copy LEN bytes from inferior's memory starting at MEMADDR
+ to debugger memory starting at MYADDR.
+ On failure (cannot read from inferior, usually because address is out
+ of bounds) returns the value of errno. */
+
+int
+read_inferior_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & - sizeof (int);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count
+ = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
+ /* Allocate buffer of that many longwords. */
+ register int *buffer = (int *) alloca (count * sizeof (int));
+ extern int errno;
+
+ /* Read all the longwords */
+ for (i = 0; i < count; i++, addr += sizeof (int))
+ {
+ errno = 0;
+ if (remote_debugging)
+ buffer[i] = remote_fetch_word (addr);
+ else
+ buffer[i] = ptrace (1, inferior_pid, addr, 0);
+ if (errno)
+ return errno;
+ }
+
+ /* Copy appropriate bytes out of the buffer. */
+ bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
+ return 0;
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR
+ to inferior's memory at MEMADDR.
+ On failure (cannot write the inferior)
+ returns the value of errno. */
+
+int
+write_inferior_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & - sizeof (int);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count
+ = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
+ /* Allocate buffer of that many longwords. */
+ register int *buffer = (int *) alloca (count * sizeof (int));
+ extern int errno;
+
+ /* Fill start and end extra bytes of buffer with existing memory data. */
+
+ if (remote_debugging)
+ buffer[0] = remote_fetch_word (addr);
+ else
+ buffer[0] = ptrace (1, inferior_pid, addr, 0);
+
+ if (count > 1)
+ {
+ if (remote_debugging)
+ buffer[count - 1]
+ = remote_fetch_word (addr + (count - 1) * sizeof (int));
+ else
+ buffer[count - 1]
+ = ptrace (1, inferior_pid,
+ addr + (count - 1) * sizeof (int), 0);
+ }
+
+ /* Copy data to be written over corresponding part of buffer */
+
+ bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
+
+ /* Write the entire buffer. */
+
+ for (i = 0; i < count; i++, addr += sizeof (int))
+ {
+ errno = 0;
+ if (remote_debugging)
+ remote_store_word (addr, buffer[i]);
+ else
+ ptrace (4, inferior_pid, addr, buffer[i]);
+ if (errno)
+ return errno;
+ }
+
+ return 0;
+}
+
+/* Work with core dump and executable files, for GDB.
+ This code would be in core.c if it weren't machine-dependent. */
+
+#ifndef N_TXTADDR
+#define N_TXTADDR(hdr) 0
+#endif /* no N_TXTADDR */
+
+#ifndef N_DATADDR
+#define N_DATADDR(hdr) hdr.a_text
+#endif /* no N_DATADDR */
+
+/* Make COFF and non-COFF names for things a little more compatible
+ to reduce conditionals later. */
+
+#ifndef COFF_FORMAT
+#ifndef AOUTHDR
+#define AOUTHDR struct exec
+#endif
+#endif
+
+extern char *sys_siglist[];
+
+
+/* Hook for `exec_file_command' command to call. */
+
+extern void (*exec_file_display_hook) ();
+
+/* File names of core file and executable file. */
+
+extern char *corefile;
+extern char *execfile;
+
+/* Descriptors on which core file and executable file are open.
+ Note that the execchan is closed when an inferior is created
+ and reopened if the inferior dies or is killed. */
+
+extern int corechan;
+extern int execchan;
+
+/* Last modification time of executable file.
+ Also used in source.c to compare against mtime of a source file. */
+
+extern int exec_mtime;
+
+/* Virtual addresses of bounds of the two areas of memory in the core file. */
+
+extern CORE_ADDR data_start;
+extern CORE_ADDR data_end;
+extern CORE_ADDR stack_start;
+extern CORE_ADDR stack_end;
+
+/* Virtual addresses of bounds of two areas of memory in the exec file.
+ Note that the data area in the exec file is used only when there is no core file. */
+
+extern CORE_ADDR text_start;
+extern CORE_ADDR text_end;
+
+extern CORE_ADDR exec_data_start;
+extern CORE_ADDR exec_data_end;
+
+/* Address in executable file of start of text area data. */
+
+extern int text_offset;
+
+/* Address in executable file of start of data area data. */
+
+extern int exec_data_offset;
+
+/* Address in core file of start of data area data. */
+
+extern int data_offset;
+
+/* Address in core file of start of stack area data. */
+
+extern int stack_offset;
+
+#ifdef COFF_FORMAT
+/* various coff data structures */
+
+extern FILHDR file_hdr;
+extern SCNHDR text_hdr;
+extern SCNHDR data_hdr;
+
+#endif /* not COFF_FORMAT */
+
+/* a.out header saved in core file. */
+
+extern AOUTHDR core_aouthdr;
+
+/* a.out header of exec file. */
+
+extern AOUTHDR exec_aouthdr;
+
+extern void validate_files ();
+
+core_file_command (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ int val;
+ extern char registers[];
+
+ /* Discard all vestiges of any previous core file
+ and mark data and stack spaces as empty. */
+
+ if (corefile)
+ free (corefile);
+ corefile = 0;
+
+ if (corechan >= 0)
+ close (corechan);
+ corechan = -1;
+
+ data_start = 0;
+ data_end = 0;
+ stack_start = STACK_END_ADDR;
+ stack_end = STACK_END_ADDR;
+
+ /* Now, if a new core file was specified, open it and digest it. */
+
+ if (filename)
+ {
+ filename = tilde_expand (filename);
+ make_cleanup (free, filename);
+
+ if (have_inferior_p ())
+ error ("To look at a core file, you must kill the inferior with \"kill\".");
+ corechan = open (filename, O_RDONLY, 0);
+ if (corechan < 0)
+ perror_with_name (filename);
+ /* 4.2-style (and perhaps also sysV-style) core dump file. */
+ {
+ struct user u;
+
+ int reg_offset;
+
+ val = myread (corechan, &u, sizeof u);
+ if (val < 0)
+ perror_with_name (filename);
+ data_start = exec_data_start;
+
+ data_end = data_start + NBPG * u.u_dsize;
+ stack_start = stack_end - NBPG * u.u_ssize;
+ data_offset = NBPG * UPAGES;
+ stack_offset = NBPG * (UPAGES + u.u_dsize);
+ reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR;
+
+ /* I don't know where to find this info.
+ So, for now, mark it as not available. */
+/* N_SET_MAGIC (core_aouthdr, 0); */
+ bzero ((char *) &core_aouthdr, sizeof core_aouthdr);
+
+ /* Read the register values out of the core file and store
+ them where `read_register' will find them. */
+
+ {
+ register int regno;
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ {
+ char buf[MAX_REGISTER_RAW_SIZE];
+
+ val = lseek (corechan, register_addr (regno, reg_offset), 0);
+ if (val < 0)
+ perror_with_name (filename);
+
+ val = myread (corechan, buf, sizeof buf);
+ if (val < 0)
+ perror_with_name (filename);
+ supply_register (regno, buf);
+ }
+ }
+ }
+ if (filename[0] == '/')
+ corefile = savestring (filename, strlen (filename));
+ else
+ {
+ corefile = concat (current_directory, "/", filename);
+ }
+
+ set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+ select_frame (get_current_frame (), 0);
+ validate_files ();
+ }
+ else if (from_tty)
+ printf ("No core file now.\n");
+}
+
+exec_file_command (filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ int val;
+
+ /* Eliminate all traces of old exec file.
+ Mark text segment as empty. */
+
+ if (execfile)
+ free (execfile);
+ execfile = 0;
+ data_start = 0;
+ data_end -= exec_data_start;
+ text_start = 0;
+ text_end = 0;
+ exec_data_start = 0;
+ exec_data_end = 0;
+ if (execchan >= 0)
+ close (execchan);
+ execchan = -1;
+
+ /* Now open and digest the file the user requested, if any. */
+
+ if (filename)
+ {
+ filename = tilde_expand (filename);
+ make_cleanup (free, filename);
+
+ execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
+ &execfile);
+ if (execchan < 0)
+ perror_with_name (filename);
+
+#ifdef COFF_FORMAT
+ {
+ int aout_hdrsize;
+ int num_sections;
+
+ if (read_file_hdr (execchan, &file_hdr) < 0)
+ error ("\"%s\": not in executable format.", execfile);
+
+ aout_hdrsize = file_hdr.f_opthdr;
+ num_sections = file_hdr.f_nscns;
+
+ if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0)
+ error ("\"%s\": can't read optional aouthdr", execfile);
+
+ if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections,
+ aout_hdrsize) < 0)
+ error ("\"%s\": can't read text section header", execfile);
+
+ if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections,
+ aout_hdrsize) < 0)
+ error ("\"%s\": can't read data section header", execfile);
+
+ text_start = exec_aouthdr.text_start;
+ text_end = text_start + exec_aouthdr.tsize;
+ text_offset = text_hdr.s_scnptr;
+ exec_data_start = exec_aouthdr.data_start;
+ exec_data_end = exec_data_start + exec_aouthdr.dsize;
+ exec_data_offset = data_hdr.s_scnptr;
+ data_start = exec_data_start;
+ data_end += exec_data_start;
+ exec_mtime = file_hdr.f_timdat;
+ }
+#else /* not COFF_FORMAT */
+ {
+ struct stat st_exec;
+
+#ifdef HEADER_SEEK_FD
+ HEADER_SEEK_FD (execchan);
+#endif
+
+ val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
+
+ if (val < 0)
+ perror_with_name (filename);
+
+ text_start = N_TXTADDR (exec_aouthdr);
+ exec_data_start = N_DATADDR (exec_aouthdr);
+
+ text_offset = N_TXTOFF (exec_aouthdr);
+ exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
+
+ text_end = text_start + exec_aouthdr.a_text;
+ exec_data_end = exec_data_start + exec_aouthdr.a_data;
+ data_start = exec_data_start;
+ data_end += exec_data_start;
+
+ fstat (execchan, &st_exec);
+ exec_mtime = st_exec.st_mtime;
+ }
+#endif /* not COFF_FORMAT */
+
+ validate_files ();
+ }
+ else if (from_tty)
+ printf ("No exec file now.\n");
+
+ /* Tell display code (if any) about the changed file name. */
+ if (exec_file_display_hook)
+ (*exec_file_display_hook) (filename);
+}
+
+/* helper functions for m-i386.h */
+
+/* stdio style buffering to minimize calls to ptrace */
+static CORE_ADDR codestream_next_addr;
+static CORE_ADDR codestream_addr;
+static unsigned char codestream_buf[sizeof (int)];
+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)
+{
+ codestream_addr = codestream_next_addr;
+ codestream_next_addr += sizeof (int);
+ codestream_off = 0;
+ codestream_cnt = sizeof (int);
+ read_memory (codestream_addr,
+ (unsigned char *)codestream_buf,
+ sizeof (int));
+
+ if (peek_flag)
+ return (codestream_peek());
+ else
+ return (codestream_get());
+}
+
+static void
+codestream_seek (place)
+{
+ codestream_next_addr = place & -sizeof (int);
+ codestream_cnt = 0;
+ codestream_fill (1);
+ while (codestream_tell() != place)
+ codestream_get ();
+}
+
+static void
+codestream_read (buf, count)
+ unsigned char *buf;
+{
+ 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
+i386_follow_jump ()
+{
+ int long_delta;
+ short short_delta;
+ char byte_delta;
+ int data16;
+ int 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 ((unsigned char *)&short_delta, 2);
+ pos += short_delta + 3; /* include size of jmp inst */
+ }
+ else
+ {
+ codestream_read ((unsigned char *)&long_delta, 4);
+ pos += long_delta + 5;
+ }
+ break;
+ case 0xeb:
+ /* relative jump, disp8 (ignore data16) */
+ codestream_read ((unsigned char *)&byte_delta, 1);
+ pos += byte_delta + 2;
+ break;
+ }
+ codestream_seek (pos + data16);
+}
+
+/*
+ * 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)
+{
+ 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 (bcmp (buf, proto1, 3) == 0)
+ pos += 3;
+ else if (bcmp (buf, proto2, 4) == 0)
+ pos += 4;
+
+ codestream_seek (pos);
+ op = codestream_get (); /* update next opcode */
+ }
+
+ if (op == 0x55) /* pushl %esp */
+ {
+ /* 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)
+ return (-1);
+ /* subl with signed byte immediate
+ * (though it wouldn't make sense to be negative)
+ */
+ return (codestream_get());
+ }
+ else if (op == 0x81)
+ {
+ /* subl with 32 bit immed */
+ int locals;
+ codestream_get();
+ if (codestream_get () != 0xec)
+ return (-1);
+ /* subl with 32 bit immediate */
+ codestream_read ((unsigned char *)&locals, 4);
+ return (locals);
+ }
+ else
+ {
+ return (0);
+ }
+ }
+ else if (op == 0xc8)
+ {
+ /* enter instruction: arg is 16 bit unsigned immed */
+ unsigned short slocals;
+ codestream_read ((unsigned char *)&slocals, 2);
+ codestream_get (); /* flush final byte of enter instruction */
+ return (slocals);
+ }
+ return (-1);
+}
+
+/* Return number of args passed to a frame.
+ Can return -1, meaning no way to tell. */
+
+/* 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
+i386_frame_num_args (fi)
+ struct frame_info fi;
+{
+ int retpc;
+ unsigned char op;
+ struct frame_info *pfi;
+
+ 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;
+ }
+ }
+}
+
+/*
+ * 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.
+ */
+
+i386_frame_find_saved_regs (fip, fsrp)
+ struct frame_info *fip;
+ struct frame_saved_regs *fsrp;
+{
+ unsigned long locals;
+ unsigned char *p;
+ unsigned char op;
+ CORE_ADDR dummy_bottom;
+ CORE_ADDR adr;
+ int i;
+
+ bzero (fsrp, sizeof *fsrp);
+
+ /* if frame is the end of a dummy, compute where the
+ * beginning would be
+ */
+ dummy_bottom = fip->frame - 4 - NUM_REGS*4 - 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 - 4;
+ for (i = 0; i < NUM_REGS; i++)
+ {
+ fsrp->regs[i] = adr;
+ adr -= 4;
+ }
+ 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;
+ fsrp->regs[op - 0x50] = adr;
+ adr -= 4;
+ }
+ }
+
+ fsrp->regs[PC_REGNUM] = fip->frame + 4;
+ fsrp->regs[FP_REGNUM] = fip->frame;
+}
+
+/* return pc of first real instruction */
+i386_skip_prologue (pc)
+{
+ unsigned char op;
+ int i;
+
+ 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 ();
+ }
+
+ i386_follow_jump ();
+
+ return (codestream_tell ());
+}
+
+i386_push_dummy_frame ()
+{
+ CORE_ADDR sp = read_register (SP_REGNUM);
+ int regnum;
+
+ 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++)
+ sp = push_word (sp, read_register (regnum));
+ write_register (SP_REGNUM, sp);
+}
+
+i386_pop_frame ()
+{
+ FRAME frame = get_current_frame ();
+ CORE_ADDR fp;
+ int regnum;
+ struct frame_saved_regs fsr;
+ struct frame_info *fi;
+
+ 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)
+ write_register (regnum, read_memory_integer (adr, 4));
+ }
+ 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 ()));
+}
+
+/* this table must line up with REGISTER_NAMES in m-i386.h */
+/* symbols like 'EAX' come from <sys/reg.h> */
+static int regmap[] =
+{
+ EAX, ECX, EDX, EBX,
+ UESP, EBP, ESI, EDI,
+ EIP, EFL, CS, SS,
+ DS, ES, FS, GS,
+};
+
+/* blockend is the value of u.u_ar0, and points to the
+ * place where GS is stored
+ */
+i386_register_u_addr (blockend, regnum)
+{
+#if 0
+ /* this will be needed if fp registers are reinstated */
+ /* for now, you can look at them with 'info float'
+ * sys5 wont let you change them with ptrace anyway
+ */
+ if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM)
+ {
+ int ubase, fpstate;
+ struct user u;
+ ubase = blockend + 4 * (SS + 1) - KSTKSZ;
+ fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u);
+ return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
+ }
+ else
+#endif
+ return (blockend + 4 * regmap[regnum]);
+
+}
+
+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 */
+}
+
+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");
+}
+
+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
+print_387_control_word (control)
+unsigned short 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
+print_387_status_word (status)
+ unsigned short 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
+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 (status);
+ }
+
+ if (ep->status != 0)
+ {
+ if (bothstatus)
+ printf ("e: ");
+ print_387_status_word (ep->status);
+ }
+
+ print_387_control_word (ep->control);
+ printf ("last exception: ");
+ 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--)
+ {
+ double val;
+
+ printf ("%s %d: ", fpreg == top ? "=>" : " ", fpreg);
+
+ 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[fpreg][i]);
+
+ i387_to_double (ep->regs[fpreg], (char *)&val);
+ printf (" %g\n", val);
+ }
+ if (ep->r0)
+ printf ("warning: reserved0 is 0x%x\n", ep->r0);
+ if (ep->r1)
+ printf ("warning: reserved1 is 0x%x\n", ep->r1);
+ if (ep->r2)
+ printf ("warning: reserved2 is 0x%x\n", ep->r2);
+ if (ep->r3)
+ printf ("warning: reserved3 is 0x%x\n", ep->r3);
+}
+
+#ifndef U_FPSTATE
+#define U_FPSTATE(u) u.u_fpstate
+#endif
+
+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;
+
+ uaddr = (char *)&u.u_fpvalid - (char *)&u;
+ if (have_inferior_p())
+ {
+ unsigned int data;
+ unsigned int mask;
+
+ rounded_addr = uaddr & -sizeof (int);
+ data = ptrace (3, inferior_pid, rounded_addr, 0);
+ mask = 0xff << ((uaddr - rounded_addr) * 8);
+
+ fpvalid = ((data & mask) != 0);
+ }
+ else
+ {
+ if (lseek (corechan, uaddr, 0) < 0)
+ perror ("seek on core file");
+ if (myread (corechan, &fpvalid, 1) < 0)
+ perror ("read on core file");
+
+ }
+
+ if (fpvalid == 0)
+ {
+ printf ("no floating point status saved\n");
+ return;
+ }
+
+ uaddr = (char *)&U_FPSTATE(u) - (char *)&u;
+ if (have_inferior_p ())
+ {
+ 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 (3, inferior_pid, rounded_addr, 0);
+ rounded_addr += sizeof (int);
+ }
+ }
+ 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;
+ }
+
+ fpstatep = (struct fpstate *)(buf + skip);
+ print_387_status (fpstatep->status, (struct env387 *)fpstatep->state);
+}
+
diff --git a/gnu/usr.bin/gdb/config/i386-pinsn.c b/gnu/usr.bin/gdb/config/i386-pinsn.c
new file mode 100644
index 0000000..649baaf
--- /dev/null
+++ b/gnu/usr.bin/gdb/config/i386-pinsn.c
@@ -0,0 +1,1812 @@
+/* Print i386 instructions for GDB, the GNU debugger.
+ Copyright (C) 1988, 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. */
+
+/*
+ * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu)
+ * July 1988
+ */
+
+/*
+ * 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 <stdio.h>
+#include <ctype.h>
+
+#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();
+
+
+#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, Xb },
+ { "scasS", eAX, Xv },
+ /* 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 */
+ { "(bad)" }, { "(bad)" }, { "(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 */
+ { "(bad)" },
+ { "(bad)" },
+ { "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 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* c8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 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 int mod;
+static int rm;
+static int reg;
+
+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 },
+ { "(bad)" },
+ },
+ /* 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;
+
+ckprefix ()
+{
+ prefixes = 0;
+ while (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 start_pc;
+
+/*
+ * disassemble the first instruction in 'inbuf'. You have to make
+ * sure all of the bytes of the instruction are filled in.
+ * 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
+ * 'outbuf' gets filled in with the disassembled instruction. it should
+ * be long enough to hold the longest disassembled instruction.
+ * 100 bytes is certainly enough, unless symbol printing is added later
+ * The function returns the length of this instruction in bytes.
+ */
+i386dis (pc, inbuf, outbuf)
+ int pc;
+ unsigned char *inbuf;
+ char *outbuf;
+{
+ struct dis386 *dp;
+ char *p;
+ int i;
+ int enter_instruction;
+ char *first, *second, *third;
+ int needcomma;
+
+ obuf[0] = 0;
+ op1out[0] = 0;
+ op2out[0] = 0;
+ op3out[0] = 0;
+
+ start_pc = pc;
+ start_codep = inbuf;
+ codep = inbuf;
+
+ ckprefix ();
+
+ 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 */
+ oappend ("fwait");
+ strcpy (outbuf, obuf);
+ 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)
+ dp = &dis386_twobyte[*++codep];
+ else
+ dp = &dis386[*codep];
+ codep++;
+ 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;
+ if (dp->op1)
+ (*dp->op1)(dp->bytemode1);
+
+ obufp = op2out;
+ if (dp->op2)
+ (*dp->op2)(dp->bytemode2);
+
+ obufp = op3out;
+ if (dp->op3)
+ (*dp->op3)(dp->bytemode3);
+ }
+
+ obufp = obuf + strlen (obuf);
+ for (i = strlen (obuf); i < 6; i++)
+ oappend (" ");
+ oappend (" ");
+
+ /* 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;
+ }
+ else
+ {
+ first = op3out;
+ second = op2out;
+ third = op1out;
+ }
+ needcomma = 0;
+ if (*first)
+ {
+ oappend (first);
+ needcomma = 1;
+ }
+ if (*second)
+ {
+ if (needcomma)
+ oappend (",");
+ oappend (second);
+ needcomma = 1;
+ }
+ if (*third)
+ {
+ if (needcomma)
+ oappend (",");
+ oappend (third);
+ }
+ strcpy (outbuf, obuf);
+ 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)",
+ },
+};
+
+
+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 && *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 */
+OP_ST (ignore)
+{
+ oappend ("%st");
+}
+
+/* ARGSUSED */
+OP_STi (ignore)
+{
+ sprintf (scratchbuf, "%%st(%d)", rm);
+ oappend (scratchbuf);
+}
+
+
+/* capital letters in template are macros */
+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;
+}
+
+oappend (s)
+char *s;
+{
+ strcpy (obufp, s);
+ obufp += strlen (s);
+ *obufp = 0;
+}
+
+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:");
+}
+
+OP_indirE (bytemode)
+{
+ oappend ("*");
+ OP_E (bytemode);
+}
+
+OP_E (bytemode)
+{
+ int disp;
+ int havesib;
+ int didoutput = 0;
+ 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;
+ }
+
+ append_prefix ();
+ if (rm == 4)
+ {
+ havesib = 1;
+ havebase = 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:
+ 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, "%d", 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 (")");
+ }
+}
+
+OP_G (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;
+ }
+}
+
+get32 ()
+{
+ int x = 0;
+
+ x = *codep++ & 0xff;
+ x |= (*codep++ & 0xff) << 8;
+ x |= (*codep++ & 0xff) << 16;
+ x |= (*codep++ & 0xff) << 24;
+ return (x);
+}
+
+get16 ()
+{
+ int x = 0;
+
+ x = *codep++ & 0xff;
+ x |= (*codep++ & 0xff) << 8;
+ return (x);
+}
+
+OP_REG (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);
+}
+
+OP_I (bytemode)
+{
+ int op;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ 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;
+ }
+ sprintf (scratchbuf, "$0x%x", op);
+ oappend (scratchbuf);
+}
+
+OP_sI (bytemode)
+{
+ int op;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ 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;
+ }
+ sprintf (scratchbuf, "$0x%x", op);
+ oappend (scratchbuf);
+}
+
+OP_J (bytemode)
+{
+ int disp;
+ int mask = -1;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ 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 disassembelr error>");
+ return;
+ }
+
+ sprintf (scratchbuf, "0x%x",
+ (start_pc + codep - start_codep + disp) & mask);
+ oappend (scratchbuf);
+}
+
+/* ARGSUSED */
+OP_SEG (dummy)
+{
+ static char *sreg[] = {
+ "%es","%cs","%ss","%ds","%fs","%gs","%?","%?",
+ };
+
+ oappend (sreg[reg]);
+}
+
+OP_DIR (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 ();
+
+ sprintf (scratchbuf, "0x%x",
+ start_pc + codep - start_codep + offset);
+ oappend (scratchbuf);
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ break;
+ }
+}
+
+/* ARGSUSED */
+OP_OFF (bytemode)
+{
+ int off;
+
+ if (aflag)
+ off = get32 ();
+ else
+ off = get16 ();
+
+ sprintf (scratchbuf, "0x%x", off);
+ oappend (scratchbuf);
+}
+
+/* ARGSUSED */
+OP_ESDI (dummy)
+{
+ oappend ("%es:(");
+ oappend (aflag ? "%edi" : "%di");
+ oappend (")");
+}
+
+/* ARGSUSED */
+OP_DSSI (dummy)
+{
+ oappend ("%ds:(");
+ oappend (aflag ? "%esi" : "%si");
+ oappend (")");
+}
+
+/* ARGSUSED */
+OP_ONE (dummy)
+{
+ oappend ("1");
+}
+
+/* ARGSUSED */
+OP_C (dummy)
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%cr%d", reg);
+ oappend (scratchbuf);
+}
+
+/* ARGSUSED */
+OP_D (dummy)
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%db%d", reg);
+ oappend (scratchbuf);
+}
+
+/* ARGSUSED */
+OP_T (dummy)
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%tr%d", reg);
+ oappend (scratchbuf);
+}
+
+OP_rm (bytemode)
+{
+ switch (bytemode)
+ {
+ case d_mode:
+ oappend (names32[rm]);
+ break;
+ case w_mode:
+ oappend (names16[rm]);
+ break;
+ }
+}
+
+/* GDB interface */
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "inferior.h"
+
+#define MAXLEN 20
+print_insn (memaddr, stream)
+ CORE_ADDR memaddr;
+ FILE *stream;
+{
+ unsigned char buffer[MAXLEN];
+ /* should be expanded if disassembler prints symbol names */
+ char outbuf[100];
+ int n;
+
+ read_memory (memaddr, buffer, MAXLEN);
+
+ n = i386dis ((int)memaddr, buffer, outbuf);
+
+ fputs (outbuf, stream);
+
+ return (n);
+}
+
diff --git a/gnu/usr.bin/gdb/config/i386bsd-dep.c b/gnu/usr.bin/gdb/config/i386bsd-dep.c
new file mode 100644
index 0000000..16286ee
--- /dev/null
+++ b/gnu/usr.bin/gdb/config/i386bsd-dep.c
@@ -0,0 +1,1889 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)i386bsd-dep.c 6.10 (Berkeley) 6/26/91";
+#endif /* not lint */
+
+/* Low level interface to ptrace, for GDB when running on the Intel 386.
+ Copyright (C) 1988, 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. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "value.h"
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <a.out.h>
+
+#ifndef N_SET_MAGIC
+#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
+#endif
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/uio.h>
+#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */
+#include <sys/user.h>
+#undef curpcb
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/ptrace.h>
+
+#include <machine/reg.h>
+
+#ifdef KERNELDEBUG
+#ifndef NEWVM
+#include <sys/vmmac.h>
+#include <machine/pte.h>
+#else
+#include <sys/proc.h> /* for curproc */
+#endif
+#include <machine/vmparam.h>
+#include <machine/cpu.h>
+#include <ctype.h>
+#include "symtab.h" /* XXX */
+
+#undef vtophys /* XXX */
+
+extern int kernel_debugging;
+
+#define KERNOFF ((unsigned)KERNBASE)
+#ifndef NEWVM
+#define INKERNEL(x) ((x) >= KERNOFF && (x) < KERNOFF + ctob(slr))
+#define INUPAGE(x) \
+ ((x) >= KERNEL_U_ADDR && (x) < KERNEL_U_ADDR + NBPG)
+#else
+#define INKERNEL(x) ((x) >= KERNOFF)
+#endif
+
+#define PT_ADDR_ANY ((caddr_t) 1)
+
+/*
+ * Convert from sysmap pte index to system virtual address & vice-versa.
+ * (why aren't these in one of the system vm macro files???)
+ */
+#define smxtob(a) (sbr + (a) * sizeof(pte))
+#define btosmx(b) (((b) - sbr) / sizeof(pte))
+
+static int ok_to_cache();
+static int found_pcb;
+#ifdef NEWVM
+static CORE_ADDR curpcb;
+static CORE_ADDR kstack;
+#endif
+
+static void setregmap();
+
+extern int errno;
+
+/*
+ * 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, arg3, arg4)
+ int request;
+ pid_t pid;
+ caddr_t arg3;
+ int arg4;
+{
+ return(ptrace(request, pid, arg3, arg4));
+}
+
+kill_inferior()
+{
+ if (remote_debugging) {
+#ifdef KERNELDEBUG
+ if (kernel_debugging)
+ /*
+ * It's a very, very bad idea to go away leaving
+ * breakpoints in a remote kernel or to leave it
+ * stopped at a breakpoint.
+ */
+ clear_breakpoints();
+#endif
+ remote_close(0);
+ inferior_died();
+ } else if (inferior_pid != 0) {
+ ptrace(PT_KILL, inferior_pid, 0, 0);
+ wait(0);
+ inferior_died();
+ }
+}
+
+/*
+ * This is used when GDB is exiting. It gives less chance of error.
+ */
+kill_inferior_fast()
+{
+ if (remote_debugging) {
+#ifdef KERNELDEBUG
+ if (kernel_debugging)
+ clear_breakpoints();
+#endif
+ remote_close(0);
+ return;
+ }
+ if (inferior_pid == 0)
+ return;
+
+ ptrace(PT_KILL, inferior_pid, 0, 0);
+ wait(0);
+}
+
+/*
+ * Resume execution of the inferior process. If STEP is nonzero, single-step
+ * it. If SIGNAL is nonzero, give it that signal.
+ */
+void
+resume(step, signal)
+ int step;
+ int signal;
+{
+ errno = 0;
+ if (remote_debugging)
+ remote_resume(step, signal);
+ else {
+ ptrace(step ? PT_STEP : PT_CONTINUE, inferior_pid,
+ PT_ADDR_ANY, signal);
+ if (errno)
+ perror_with_name("ptrace");
+ }
+}
+
+#ifdef ATTACH_DETACH
+extern int attach_flag;
+
+/*
+ * Start debugging the process whose number is PID.
+ */
+attach(pid)
+ int pid;
+{
+ errno = 0;
+ ptrace(PT_ATTACH, pid, 0, 0);
+ if (errno)
+ perror_with_name("ptrace");
+ 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;
+{
+ errno = 0;
+ ptrace(PT_DETACH, inferior_pid, PT_ADDR_ANY, signal);
+ if (errno)
+ perror_with_name("ptrace");
+ attach_flag = 0;
+}
+#endif /* ATTACH_DETACH */
+
+static unsigned int
+get_register_offset()
+{
+ unsigned int offset;
+ struct user u; /* XXX */
+ unsigned int flags = (char *) &u.u_pcb.pcb_flags - (char *) &u;
+
+ setregmap(ptrace(PT_READ_U, inferior_pid, (caddr_t)flags, 0));
+
+#ifdef NEWVM
+ offset = (char *) &u.u_kproc.kp_proc.p_regs - (char *) &u;
+ offset = ptrace(PT_READ_U, inferior_pid, (caddr_t)offset, 0) -
+ USRSTACK;
+#else
+ offset = (char *) &u.u_ar0 - (char *) &u;
+ offset = ptrace(PT_READ_U, inferior_pid, (caddr_t)offset, 0) -
+ KERNEL_U_ADDR;
+#endif
+
+ return offset;
+}
+
+void
+fetch_inferior_registers()
+{
+ register int regno;
+ register unsigned int regaddr;
+ char buf[MAX_REGISTER_RAW_SIZE];
+ register int i;
+ unsigned int offset;
+
+ if (remote_debugging) {
+ extern char registers[];
+
+ remote_fetch_registers(registers);
+ return;
+ }
+
+ offset = get_register_offset();
+
+ for (regno = 0; regno < NUM_REGS; regno++) {
+ regaddr = register_addr(regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE(regno); i += sizeof(int)) {
+ *(int *)&buf[i] = ptrace(PT_READ_U, inferior_pid,
+ (caddr_t)regaddr, 0);
+ regaddr += sizeof(int);
+ }
+ supply_register(regno, buf);
+ }
+}
+
+/*
+ * 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).
+ */
+store_inferior_registers(regno)
+ int regno;
+{
+ register unsigned int regaddr;
+ char buf[80];
+ extern char registers[];
+ register int i;
+ unsigned int offset;
+
+ if (remote_debugging) {
+ extern char registers[];
+
+ remote_store_registers(registers);
+ return;
+ }
+
+ offset = get_register_offset();
+
+ if (regno >= 0) {
+ regaddr = register_addr(regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE(regno); i += sizeof(int)) {
+ errno = 0;
+ ptrace(PT_WRITE_U, inferior_pid, (caddr_t)regaddr,
+ *(int *) &registers[REGISTER_BYTE(regno) + i]);
+ if (errno != 0) {
+ sprintf(buf, "writing register number %d(%d)",
+ regno, i);
+ perror_with_name(buf);
+ }
+ regaddr += sizeof(int);
+ }
+ } else
+ for (regno = 0; regno < NUM_REGS; regno++) {
+ regaddr = register_addr(regno, offset);
+ for (i = 0; i < REGISTER_RAW_SIZE(regno);
+ i += sizeof(int)) {
+ errno = 0;
+ ptrace(PT_WRITE_U, inferior_pid,
+ (caddr_t)regaddr,
+ *(int *) &registers[REGISTER_BYTE(regno) + i]);
+ if (errno != 0) {
+ sprintf(buf,
+ "writing register number %d(%d)",
+ regno, i);
+ perror_with_name(buf);
+ }
+ regaddr += sizeof(int);
+ }
+ }
+}
+
+/*
+ * Copy LEN bytes from inferior's memory starting at MEMADDR to debugger
+ * memory starting at MYADDR. On failure (cannot read from inferior, usually
+ * because address is out of bounds) returns the value of errno.
+ */
+int
+read_inferior_memory(memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & -sizeof(int);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count = (((memaddr + len) - addr) + sizeof(int) - 1) /
+ sizeof(int);
+ /* Allocate buffer of that many longwords. */
+ register int *buffer = (int *) alloca(count * sizeof(int));
+ extern int errno;
+
+ if (remote_debugging)
+ return (remote_read_inferior_memory(memaddr, myaddr, len));
+
+ /* Read all the longwords */
+ errno = 0;
+ for (i = 0; i < count && errno == 0; i++, addr += sizeof(int))
+ buffer[i] = ptrace(PT_READ_I, inferior_pid, (caddr_t)addr, 0);
+
+ /* Copy appropriate bytes out of the buffer. */
+ bcopy((char *) buffer + (memaddr & (sizeof(int) - 1)), myaddr, len);
+ return(errno);
+}
+
+/*
+ * Copy LEN bytes of data from debugger memory at MYADDR to inferior's memory
+ * at MEMADDR. On failure (cannot write the inferior) returns the value of
+ * errno.
+ */
+
+int
+write_inferior_memory(memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ /* Round starting address down to longword boundary. */
+ register CORE_ADDR addr = memaddr & -sizeof(int);
+ /* Round ending address up; get number of longwords that makes. */
+ register int count = (((memaddr + len) - addr) + sizeof(int) - 1) /
+ sizeof(int);
+ /* Allocate buffer of that many longwords. */
+ register int *buffer = (int *) alloca(count * sizeof(int));
+ extern int errno;
+
+ /*
+ * Fill start and end extra bytes of buffer with existing memory
+ * data.
+ */
+ if (remote_debugging)
+ return (remote_write_inferior_memory(memaddr, myaddr, len));
+
+ /*
+ * Fill start and end extra bytes of buffer with existing memory
+ * data.
+ */
+ buffer[0] = ptrace(PT_READ_I, inferior_pid, (caddr_t)addr, 0);
+
+ if (count > 1)
+ buffer[count - 1] = ptrace(PT_READ_I, inferior_pid,
+ (caddr_t)addr + (count - 1) * sizeof(int), 0);
+
+ /* Copy data to be written over corresponding part of buffer */
+
+ bcopy(myaddr, (char *) buffer + (memaddr & (sizeof(int) - 1)), len);
+
+ /* Write the entire buffer. */
+
+ errno = 0;
+ for (i = 0; i < count && errno == 0; i++, addr += sizeof(int))
+ ptrace(PT_WRITE_I, inferior_pid, (caddr_t)addr, buffer[i]);
+
+ return(errno);
+}
+
+
+/*
+ * Work with core dump and executable files, for GDB.
+ * This code would be in core.c if it weren't machine-dependent.
+ */
+
+#ifndef N_TXTADDR
+#define N_TXTADDR(hdr) 0
+#endif /* no N_TXTADDR */
+
+#ifndef N_DATADDR
+#define N_DATADDR(hdr) hdr.a_text
+#endif /* no N_DATADDR */
+
+/*
+ * Make COFF and non-COFF names for things a little more compatible to reduce
+ * conditionals later.
+ */
+
+#ifndef AOUTHDR
+#define AOUTHDR struct exec
+#endif
+
+extern char *sys_siglist[];
+
+
+/* Hook for `exec_file_command' command to call. */
+
+extern void (*exec_file_display_hook) ();
+
+/* File names of core file and executable file. */
+
+extern char *corefile;
+extern char *execfile;
+
+/* Descriptors on which core file and executable file are open.
+ Note that the execchan is closed when an inferior is created
+ and reopened if the inferior dies or is killed. */
+
+extern int corechan;
+extern int execchan;
+
+/* Last modification time of executable file.
+ Also used in source.c to compare against mtime of a source file. */
+
+extern int exec_mtime;
+
+/* Virtual addresses of bounds of the two areas of memory in the core file. */
+
+extern CORE_ADDR data_start;
+extern CORE_ADDR data_end;
+extern CORE_ADDR stack_start;
+extern CORE_ADDR stack_end;
+
+/* Virtual addresses of bounds of two areas of memory in the exec file.
+ Note that the data area in the exec file is used only when there is no core file. */
+
+extern CORE_ADDR text_start;
+extern CORE_ADDR text_end;
+
+extern CORE_ADDR exec_data_start;
+extern CORE_ADDR exec_data_end;
+
+/* Address in executable file of start of text area data. */
+
+extern int text_offset;
+
+/* Address in executable file of start of data area data. */
+
+extern int exec_data_offset;
+
+/* Address in core file of start of data area data. */
+
+extern int data_offset;
+
+/* Address in core file of start of stack area data. */
+
+extern int stack_offset;
+
+/* a.out header saved in core file. */
+
+extern AOUTHDR core_aouthdr;
+
+/* a.out header of exec file. */
+
+extern AOUTHDR exec_aouthdr;
+
+extern void validate_files ();
+
+extern int (*core_file_hook)();
+
+#ifdef KERNELDEBUG
+/*
+ * Kernel debugging routines.
+ */
+
+#define IOTOP 0x100000 /* XXX should get this from include file */
+#define IOBASE 0xa0000 /* XXX should get this from include file */
+
+static CORE_ADDR file_offset;
+static CORE_ADDR lowram;
+static CORE_ADDR sbr;
+static CORE_ADDR slr;
+static struct pcb pcb;
+
+static CORE_ADDR
+ksym_lookup(name)
+ char *name;
+{
+ struct symbol *sym;
+ int i;
+
+ if ((i = lookup_misc_func(name)) < 0)
+ error("kernel symbol `%s' not found.", name);
+
+ return (misc_function_vector[i].address);
+}
+
+/*
+ * return true if 'len' bytes starting at 'addr' can be read out as
+ * longwords and/or locally cached (this is mostly for memory mapped
+ * i/o register access when debugging remote kernels).
+ *
+ * XXX the HP code does this differently with NEWVM
+ */
+static int
+ok_to_cache(addr, len)
+{
+ static CORE_ADDR atdevbase;
+
+ if (! atdevbase)
+ atdevbase = ksym_lookup("atdevbase");
+
+ if (addr >= atdevbase && addr < atdevbase + (IOTOP - IOBASE))
+ return (0);
+
+ return (1);
+}
+
+static
+physrd(addr, dat, len)
+ u_int addr;
+ char *dat;
+{
+ if (lseek(corechan, addr - file_offset, L_SET) == -1)
+ return (-1);
+ if (read(corechan, dat, len) != len)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * When looking at kernel data space through /dev/mem or with a core file, do
+ * virtual memory mapping.
+ */
+#ifdef NEWVM
+static CORE_ADDR
+vtophys(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 = vtophys(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(v, (char *)&pte, sizeof pte) || 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(v, (char *) &pte, sizeof(pte)) || 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);
+}
+#else
+static CORE_ADDR
+vtophys(addr)
+ CORE_ADDR addr;
+{
+ CORE_ADDR v;
+ struct pte pte;
+ CORE_ADDR oldaddr = addr;
+
+ if (found_pcb == 0 && INUPAGE(addr)) {
+ static CORE_ADDR pSwtchmap;
+
+ if (pSwtchmap == 0)
+ pSwtchmap = vtophys(ksym_lookup("Swtchmap"));
+ addr = pSwtchmap;
+ } else if (INKERNEL(addr)) {
+ /*
+ * In system space get system pte. If valid or reclaimable
+ * then physical address is combination of its page number
+ * and the page offset of the original address.
+ */
+ addr = smxtob(btop(addr - KERNOFF)) - KERNOFF;
+ } else {
+ v = btop(addr);
+ if (v < pcb.pcb_p0lr)
+ addr = (CORE_ADDR) pcb.pcb_p0br +
+ v * sizeof (struct pte);
+ else if (v >= pcb.pcb_p1lr && v < P1PAGES)
+ addr = (CORE_ADDR) pcb.pcb_p0br +
+ ((pcb.pcb_szpt * NPTEPG - HIGHPAGES) -
+ (BTOPUSRSTACK - v)) * sizeof (struct pte);
+ else
+ return (~0);
+
+ /*
+ * For p0/p1 address, user-level page table should be in
+ * kernel vm. Do second-level indirect by recursing.
+ */
+ if (!INKERNEL(addr))
+ return (~0);
+
+ addr = vtophys(addr);
+ }
+ /*
+ * Addr is now address of the pte of the page we are interested in;
+ * get the pte and paste up the physical address.
+ */
+ if (physrd(addr, (char *) &pte, sizeof(pte)))
+ return (~0);
+
+ if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0))
+ return (~0);
+
+ addr = (CORE_ADDR)ptob(pte.pg_pfnum) + (oldaddr & PGOFSET);
+#if 0
+ printf("vtophys(%x) -> %x\n", oldaddr, addr);
+#endif
+ return (addr);
+}
+
+#endif
+
+static
+kvread(addr)
+ CORE_ADDR addr;
+{
+ CORE_ADDR paddr = vtophys(addr);
+
+ if (paddr != ~0)
+ if (physrd(paddr, (char *)&addr, sizeof(addr)) == 0);
+ return (addr);
+
+ return (~0);
+}
+
+static void
+read_pcb(uaddr)
+ u_int uaddr;
+{
+ int i;
+ int *pcb_regs = (int *)&pcb;
+
+#ifdef NEWVM
+ if (physrd(uaddr, (char *)&pcb, sizeof pcb))
+ error("cannot read pcb at %x\n", uaddr);
+ printf("current pcb at %x\n", uaddr);
+#else
+ if (physrd(uaddr, (char *)&pcb, sizeof pcb))
+ error("cannot read pcb at %x\n", uaddr);
+ printf("p0br %x p0lr %x p1br %x p1lr %x\n",
+ pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr);
+#endif
+
+ /*
+ * 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]);
+
+ /* XXX 80387 registers? */
+}
+
+static void
+setup_kernel_debugging()
+{
+ struct stat stb;
+ int devmem = 0;
+ CORE_ADDR addr;
+
+ fstat(corechan, &stb);
+ if ((stb.st_mode & S_IFMT) == S_IFCHR && stb.st_rdev == makedev(2, 0))
+ devmem = 1;
+
+#ifdef NEWVM
+ physrd(ksym_lookup("IdlePTD") - KERNOFF, &sbr, sizeof sbr);
+ slr = 2 * NPTEPG; /* XXX temporary */
+ printf("IdlePTD %x\n", sbr);
+ curpcb = ksym_lookup("curpcb") - KERNOFF;
+ physrd(curpcb, &curpcb, sizeof curpcb);
+ kstack = ksym_lookup("kstack");
+#else
+ sbr = ksym_lookup("Sysmap");
+ slr = ksym_lookup("Syssize");
+ printf("sbr %x slr %x\n", sbr, slr);
+#endif
+
+ /*
+ * pcb where "panic" saved registers in first thing in current
+ * u area.
+ */
+#ifndef NEWVM
+ read_pcb(vtophys(ksym_lookup("u")));
+#endif
+ found_pcb = 1;
+ if (!devmem) {
+ /* find stack frame */
+ CORE_ADDR panicstr;
+ char buf[256];
+ register char *cp;
+
+ panicstr = kvread(ksym_lookup("panicstr"));
+ if (panicstr == ~0)
+ return;
+ (void) kernel_core_file_hook(panicstr, buf, sizeof(buf));
+ for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++)
+ if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp)))
+ *cp = '?';
+ if (*cp)
+ *cp = '\0';
+ printf("panic: %s\n", buf);
+ read_pcb(ksym_lookup("dumppcb") - KERNOFF);
+ }
+#ifdef NEWVM
+ else
+ read_pcb(vtophys(kstack));
+#endif
+
+ stack_start = USRSTACK;
+ stack_end = USRSTACK + ctob(UPAGES);
+}
+
+set_paddr_command(arg)
+ char *arg;
+{
+ u_int uaddr;
+
+ if (!arg)
+ error_no_arg("ps-style address for new current process");
+ if (!kernel_debugging)
+ error("not debugging kernel");
+ uaddr = (u_int) parse_and_eval_address(arg);
+#ifndef NEWVM
+ read_pcb(ctob(uaddr));
+#else
+ /* p_addr is now a pcb virtual address */
+ read_pcb(vtophys(uaddr));
+ curpcb = uaddr;
+#endif
+
+ flush_cached_frames();
+ set_current_frame(create_new_frame(read_register(FP_REGNUM), read_pc()));
+ select_frame(get_current_frame(), 0);
+}
+
+/*
+ * read len bytes from kernel virtual address 'addr' into local
+ * buffer 'buf'. Return 0 if read ok, 1 otherwise. On read
+ * errors, portion of buffer not read is zeroed.
+ */
+kernel_core_file_hook(addr, buf, len)
+ CORE_ADDR addr;
+ char *buf;
+ int len;
+{
+ int i;
+ CORE_ADDR paddr;
+
+ while (len > 0) {
+ paddr = vtophys(addr);
+ if (paddr == ~0) {
+ bzero(buf, len);
+ return (1);
+ }
+ /* we can't read across a page boundary */
+ i = min(len, NBPG - (addr & PGOFSET));
+ if (physrd(paddr, buf, i)) {
+ bzero(buf, len);
+ return (1);
+ }
+ buf += i;
+ addr += i;
+ len -= i;
+ }
+ return (0);
+}
+#endif
+
+core_file_command(filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ int val;
+ extern char registers[];
+#ifdef KERNELDEBUG
+ struct stat stb;
+#endif
+
+ /*
+ * Discard all vestiges of any previous core file and mark data and
+ * stack spaces as empty.
+ */
+ if (corefile)
+ free(corefile);
+ corefile = 0;
+ core_file_hook = 0;
+
+ if (corechan >= 0)
+ close(corechan);
+ corechan = -1;
+
+ /* Now, if a new core file was specified, open it and digest it. */
+
+ if (filename == 0) {
+ if (from_tty)
+ printf("No core file now.\n");
+ return;
+ }
+ filename = tilde_expand(filename);
+ make_cleanup(free, filename);
+ if (have_inferior_p())
+ error("To look at a core file, you must kill the inferior with \"kill\".");
+ corechan = open(filename, O_RDONLY, 0);
+ if (corechan < 0)
+ perror_with_name(filename);
+
+#ifdef KERNELDEBUG
+ fstat(corechan, &stb);
+
+ if (kernel_debugging) {
+ setup_kernel_debugging();
+ core_file_hook = kernel_core_file_hook;
+ } else if ((stb.st_mode & S_IFMT) == S_IFCHR &&
+ stb.st_rdev == makedev(2, 1)) {
+ /* looking at /dev/kmem */
+ data_offset = data_start = KERNOFF;
+ data_end = ~0; /* XXX */
+ stack_end = stack_start = data_end;
+ } else
+#endif
+ {
+ /*
+ * 4.2-style core dump file.
+ */
+ struct user u;
+ unsigned int reg_offset;
+
+ val = myread(corechan, &u, sizeof u);
+ if (val < 0)
+ perror_with_name("Not a core file: reading upage");
+ if (val != sizeof u)
+ error("Not a core file: could only read %d bytes", val);
+
+ /*
+ * We are depending on exec_file_command having been
+ * called previously to set exec_data_start. Since
+ * the executable and the core file share the same
+ * text segment, the address of the data segment will
+ * be the same in both.
+ */
+ data_start = exec_data_start;
+
+#ifndef NEWVM
+ data_end = data_start + NBPG * u.u_dsize;
+ stack_start = stack_end - NBPG * u.u_ssize;
+ data_offset = NBPG * UPAGES;
+ stack_offset = NBPG * (UPAGES + u.u_dsize);
+
+ /*
+ * Some machines put an absolute address in here and
+ * some put the offset in the upage of the regs.
+ */
+ reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR;
+#else
+ stack_end = (CORE_ADDR) u.u_kproc.kp_eproc.e_vm.vm_maxsaddr
+ + MAXSSIZ;
+
+ data_end = data_start +
+ NBPG * u.u_kproc.kp_eproc.e_vm.vm_dsize;
+ stack_start = stack_end -
+ NBPG * u.u_kproc.kp_eproc.e_vm.vm_ssize;
+ data_offset = NBPG * UPAGES;
+ stack_offset = NBPG *
+ (UPAGES + u.u_kproc.kp_eproc.e_vm.vm_dsize);
+
+ reg_offset = (int) u.u_kproc.kp_proc.p_regs - USRSTACK;
+#endif
+
+ setregmap(u.u_pcb.pcb_flags);
+
+ /*
+ * I don't know where to find this info. So, for now,
+ * mark it as not available.
+ */
+ /* N_SET_MAGIC (core_aouthdr, 0); */
+ bzero ((char *) &core_aouthdr, sizeof core_aouthdr);
+
+ /*
+ * Read the register values out of the core file and
+ * store them where `read_register' will find them.
+ */
+ {
+ register int regno;
+
+ for (regno = 0; regno < NUM_REGS; regno++) {
+ char buf[MAX_REGISTER_RAW_SIZE];
+
+ val = lseek(corechan, register_addr(regno, reg_offset), 0);
+ if (val < 0
+ || (val = myread(corechan, buf, sizeof buf)) < 0) {
+ char *buffer = (char *) alloca(strlen(reg_names[regno]) + 30);
+ strcpy(buffer, "Reading register ");
+ strcat(buffer, reg_names[regno]);
+ perror_with_name(buffer);
+ }
+ supply_register(regno, buf);
+ }
+ }
+ }
+#endif
+ if (filename[0] == '/')
+ corefile = savestring(filename, strlen(filename));
+ else
+ corefile = concat(current_directory, "/", filename);
+
+ set_current_frame(create_new_frame(read_register(FP_REGNUM),
+ read_pc()));
+ select_frame(get_current_frame(), 0);
+ validate_files();
+}
+
+exec_file_command(filename, from_tty)
+ char *filename;
+ int from_tty;
+{
+ int val;
+
+ /*
+ * Eliminate all traces of old exec file. Mark text segment as empty.
+ */
+
+ if (execfile)
+ free(execfile);
+ execfile = 0;
+ data_start = 0;
+ data_end = 0;
+ stack_start = 0;
+ stack_end = 0;
+ text_start = 0;
+ text_end = 0;
+ exec_data_start = 0;
+ exec_data_end = 0;
+ if (execchan >= 0)
+ close(execchan);
+ execchan = -1;
+
+ /* Now open and digest the file the user requested, if any. */
+
+ if (filename) {
+ filename = tilde_expand(filename);
+ make_cleanup(free, filename);
+
+ execchan = openp(getenv("PATH"), 1, filename, O_RDONLY, 0,
+ &execfile);
+ if (execchan < 0)
+ perror_with_name(filename);
+
+ {
+ struct stat st_exec;
+
+#ifdef HEADER_SEEK_FD
+ HEADER_SEEK_FD(execchan);
+#endif
+
+ val = myread(execchan, &exec_aouthdr, sizeof(AOUTHDR));
+
+ if (val < 0)
+ perror_with_name(filename);
+
+#ifdef KERNELDEBUG
+ if (kernel_debugging) {
+ /* Gross and disgusting XXX */
+ text_start = KERNTEXT_BASE;
+ exec_data_start = KERNTEXT_BASE +
+ (exec_aouthdr.a_text + 4095) & ~ 4095;
+ } else {
+#endif
+ text_start = N_TXTADDR(exec_aouthdr);
+ exec_data_start = N_DATADDR(exec_aouthdr);
+#ifdef KERNELDEBUG
+ }
+#endif
+
+ text_offset = N_TXTOFF(exec_aouthdr);
+ exec_data_offset = N_TXTOFF(exec_aouthdr) + exec_aouthdr.a_text;
+
+ text_end = text_start + exec_aouthdr.a_text;
+ exec_data_end = exec_data_start + exec_aouthdr.a_data;
+
+ fstat(execchan, &st_exec);
+ exec_mtime = st_exec.st_mtime;
+ }
+
+ validate_files();
+ } else if (from_tty)
+ printf("No exec file now.\n");
+
+ /* Tell display code (if any) about the changed file name. */
+ if (exec_file_display_hook)
+ (*exec_file_display_hook) (filename);
+}
+
+int dummy_code[] = {
+ 0xb8909090, /* nop; nop; nop; movl $0x32323232,%eax */
+ 0x32323232,
+#define DUMMY_CALL_INDEX 1
+ 0x90ccd0ff, /* call %eax; int3; nop */
+};
+
+/*
+ * Build `dummy' call instructions on inferior's stack to cause
+ * it to call a subroutine.
+ *
+ * N.B. - code in wait_for_inferior requires that sp < pc < fp when
+ * we take the trap 2 above so it will recognize that we stopped
+ * at a `dummy' call. So, after the call sp is *not* decremented
+ * to clean the arguments, code & other stuff we lay on the stack.
+ * Since the regs are restored to saved values at the breakpoint,
+ * sp will get reset correctly. Also, this restore means we don't
+ * have to construct frame linkage info to save pc & fp. The lack
+ * of frame linkage means we can't do a backtrace, etc., if the
+ * called function gets a fault or hits a breakpoint but code in
+ * run_stack_dummy makes this impossible anyway.
+ */
+CORE_ADDR
+setup_dummy(sp, funaddr, nargs, args, struct_return_bytes, pushfn)
+ CORE_ADDR sp;
+ CORE_ADDR funaddr;
+ int nargs;
+ value *args;
+ int struct_return_bytes;
+ CORE_ADDR (*pushfn)();
+{
+ int padding, i;
+ CORE_ADDR top = sp, struct_addr, pc;
+
+ i = arg_stacklen(nargs, args) + struct_return_bytes
+ + sizeof(dummy_code);
+ if (i & 3)
+ padding = 4 - (i & 3);
+ else
+ padding = 0;
+ pc = sp - sizeof(dummy_code);
+ sp = pc - padding - struct_return_bytes;
+ struct_addr = sp;
+ while (--nargs >= 0)
+ sp = (*pushfn)(sp, *args++);
+ if (struct_return_bytes)
+ STORE_STRUCT_RETURN(struct_addr, sp);
+ write_register(SP_REGNUM, sp);
+
+ dummy_code[DUMMY_CALL_INDEX] = (int)funaddr;
+ write_memory(pc, (char *)dummy_code, sizeof(dummy_code));
+
+ return pc;
+}
+
+/* helper functions for m-i386.h */
+
+/* stdio style buffering to minimize calls to ptrace */
+static CORE_ADDR codestream_next_addr;
+static CORE_ADDR codestream_addr;
+static unsigned char codestream_buf[sizeof (int)];
+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)
+{
+ codestream_addr = codestream_next_addr;
+ codestream_next_addr += sizeof (int);
+ codestream_off = 0;
+ codestream_cnt = sizeof (int);
+ read_memory (codestream_addr,
+ (unsigned char *)codestream_buf,
+ sizeof (int));
+
+ if (peek_flag)
+ return (codestream_peek());
+ else
+ return (codestream_get());
+}
+
+static void
+codestream_seek (place)
+{
+ codestream_next_addr = place & -sizeof (int);
+ codestream_cnt = 0;
+ codestream_fill (1);
+ while (codestream_tell() != place)
+ codestream_get ();
+}
+
+static void
+codestream_read (buf, count)
+ unsigned char *buf;
+{
+ 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
+i386_follow_jump ()
+{
+ int long_delta;
+ short short_delta;
+ char byte_delta;
+ int data16;
+ int 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 ((unsigned char *)&short_delta, 2);
+ pos += short_delta + 3; /* include size of jmp inst */
+ }
+ else
+ {
+ codestream_read ((unsigned char *)&long_delta, 4);
+ pos += long_delta + 5;
+ }
+ break;
+ case 0xeb:
+ /* relative jump, disp8 (ignore data16) */
+ codestream_read ((unsigned char *)&byte_delta, 1);
+ pos += byte_delta + 2;
+ break;
+ }
+ codestream_seek (pos + data16);
+}
+
+/*
+ * 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)
+{
+ 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 (bcmp (buf, proto1, 3) == 0)
+ pos += 3;
+ else if (bcmp (buf, proto2, 4) == 0)
+ pos += 4;
+
+ codestream_seek (pos);
+ op = codestream_get (); /* update next opcode */
+ }
+
+ if (op == 0x55) /* pushl %esp */
+ {
+ /* 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)
+ return (-1);
+ /* subl with signed byte immediate
+ * (though it wouldn't make sense to be negative)
+ */
+ return (codestream_get());
+ }
+ else if (op == 0x81)
+ {
+ /* subl with 32 bit immed */
+ int locals;
+ codestream_get();
+ if (codestream_get () != 0xec)
+ return (-1);
+ /* subl with 32 bit immediate */
+ codestream_read ((unsigned char *)&locals, 4);
+ return (locals);
+ }
+ else
+ {
+ return (0);
+ }
+ }
+ else if (op == 0xc8)
+ {
+ /* enter instruction: arg is 16 bit unsigned immed */
+ unsigned short slocals;
+ codestream_read ((unsigned char *)&slocals, 2);
+ codestream_get (); /* flush final byte of enter instruction */
+ return (slocals);
+ }
+ return (-1);
+}
+
+/* Return number of args passed to a frame.
+ Can return -1, meaning no way to tell. */
+
+/* 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
+i386_frame_num_args (fi)
+ struct frame_info fi;
+{
+ int retpc;
+ unsigned char op;
+ struct frame_info *pfi;
+
+ 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;
+ }
+ }
+}
+
+/*
+ * 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.
+ */
+
+i386_frame_find_saved_regs (fip, fsrp)
+ struct frame_info *fip;
+ struct frame_saved_regs *fsrp;
+{
+ unsigned long locals;
+ unsigned char *p;
+ unsigned char op;
+ CORE_ADDR dummy_bottom;
+ CORE_ADDR adr;
+ int i;
+
+ bzero (fsrp, sizeof *fsrp);
+
+#if 0
+ /* if frame is the end of a dummy, compute where the
+ * beginning would be
+ */
+ dummy_bottom = fip->frame - 4 - NUM_REGS*4 - 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 - 4;
+ for (i = 0; i < NUM_REGS; i++)
+ {
+ fsrp->regs[i] = adr;
+ adr -= 4;
+ }
+ return;
+ }
+#endif
+
+ 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;
+ fsrp->regs[op - 0x50] = adr;
+ adr -= 4;
+ }
+ }
+
+ fsrp->regs[PC_REGNUM] = fip->frame + 4;
+ fsrp->regs[FP_REGNUM] = fip->frame;
+}
+
+/* return pc of first real instruction */
+i386_skip_prologue (pc)
+{
+ unsigned char op;
+ int i;
+
+ 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 ();
+ }
+
+ i386_follow_jump ();
+
+ return (codestream_tell ());
+}
+
+i386_pop_frame ()
+{
+ FRAME frame = get_current_frame ();
+ CORE_ADDR fp;
+ int regnum;
+ struct frame_saved_regs fsr;
+ struct frame_info *fi;
+
+ 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)
+ write_register (regnum, read_memory_integer (adr, 4));
+ }
+ 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 ()));
+}
+
+/* this table must line up with REGISTER_NAMES in m-i386.h */
+/* symbols like 'EAX' come from <sys/reg.h> */
+static int trapmap[] =
+{
+ tEAX, tECX, tEDX, tEBX,
+ tESP, tEBP, tESI, tEDI,
+ tEIP, tEFLAGS, tCS, tSS,
+ tDS, tES, tES, tES /* lies: no fs or gs */
+};
+#if defined(FM_TRAP) || defined(EX_TRAPSTK)
+static int syscallmap[] =
+{
+ sEAX, sECX, sEDX, sEBX,
+ sESP, sEBP, sESI, sEDI,
+ sEIP, sEFLAGS, sCS, sSS,
+ sCS, sCS, sCS, sCS /* lies: no ds, es, fs or gs */
+};
+#endif
+static int *regmap;
+
+static void
+setregmap(flags)
+ int flags;
+{
+#ifdef FM_TRAP
+ regmap = flags & FM_TRAP ? trapmap: syscallmap;
+#elif EX_TRAPSTK
+ regmap = flags & EX_TRAPSTK ? trapmap : syscallmap;
+#else
+ regmap = trapmap; /* the lesser evil */
+#endif
+}
+
+/* blockend is the value of u.u_ar0, and points to the
+ * place where GS is stored
+ */
+i386_register_u_addr (blockend, regnum)
+{
+#if 0
+ /* this will be needed if fp registers are reinstated */
+ /* for now, you can look at them with 'info float'
+ * sys5 wont let you change them with ptrace anyway
+ */
+ if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM)
+ {
+ int ubase, fpstate;
+ struct user u;
+ ubase = blockend + 4 * (SS + 1) - KSTKSZ;
+ fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u);
+ return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
+ }
+ else
+#endif
+ return (blockend + 4 * regmap[regnum]);
+}
+
+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 */
+}
+
+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");
+}
+
+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
+print_387_control_word (control)
+unsigned short 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
+print_387_status_word (status)
+ unsigned short 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
+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 (status);
+ }
+
+ if (ep->status != 0)
+ {
+ if (bothstatus)
+ printf ("e: ");
+ print_387_status_word (ep->status);
+ }
+
+ print_387_control_word (ep->control);
+ printf ("last exception: ");
+ 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 `p->regs.
+ */
+ st_regno = (fpreg + 8 - top) & 0x7;
+
+ 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);
+ }
+#if 0 /* reserved fields are always 0xffff on 486's */
+ if (ep->r0)
+ printf ("warning: reserved0 is 0x%x\n", ep->r0);
+ if (ep->r1)
+ printf ("warning: reserved1 is 0x%x\n", ep->r1);
+ if (ep->r2)
+ printf ("warning: reserved2 is 0x%x\n", ep->r2);
+ if (ep->r3)
+ printf ("warning: reserved3 is 0x%x\n", ep->r3);
+#endif
+}
+
+#ifdef __386BSD__
+#define fpstate save87
+#define U_FPSTATE(u) u.u_pcb.pcb_savefpu
+#endif
+
+#ifndef U_FPSTATE
+#define U_FPSTATE(u) u.u_fpstate
+#endif
+
+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;
+
+#ifndef __386BSD__ /* XXX - look at pcb flags */
+ uaddr = (char *)&u.u_fpvalid - (char *)&u;
+ if (have_inferior_p())
+ {
+ unsigned int data;
+ unsigned int mask;
+
+ rounded_addr = uaddr & -sizeof (int);
+ data = ptrace (PT_READ_U, inferior_pid, (caddr_t)rounded_addr, 0);
+ mask = 0xff << ((uaddr - rounded_addr) * 8);
+
+ fpvalid = ((data & mask) != 0);
+ }
+ else
+ {
+ if (lseek (corechan, uaddr, 0) < 0)
+ perror ("seek on core file");
+ if (myread (corechan, &fpvalid, 1) < 0)
+ perror ("read on core file");
+
+ }
+
+ if (fpvalid == 0)
+ {
+ printf ("no floating point status saved\n");
+ return;
+ }
+#endif /* not __386BSD__ */
+
+ uaddr = (char *)&U_FPSTATE(u) - (char *)&u;
+ if (have_inferior_p ())
+ {
+ 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 (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;
+ }
+
+#ifdef __386BSD__
+ print_387_status (0, (struct env387 *)buf);
+#else
+ fpstatep = (struct fpstate *)(buf + skip);
+ print_387_status (fpstatep->status, (struct env387 *)fpstatep->state);
+#endif
+}
+
+void
+_initialize_i386bsd_dep()
+{
+#ifdef KERNELDEBUG
+ add_com ("process-address", class_obscure, set_paddr_command,
+ "The process identified by (ps-style) ADDR becomes the\n\
+\"current\" process context for kernel debugging.");
+ add_com_alias ("paddr", "process-address", class_obscure, 0);
+#endif
+}
diff --git a/gnu/usr.bin/gdb/config/m-i386-sv32.h b/gnu/usr.bin/gdb/config/m-i386-sv32.h
new file mode 100644
index 0000000..38fb4eb
--- /dev/null
+++ b/gnu/usr.bin/gdb/config/m-i386-sv32.h
@@ -0,0 +1,28 @@
+/* Macro defintions for i386, running System V 3.2.
+ Copyright (C) 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. */
+
+#include "m-i386.h"
+
+/* Apparently there is inconsistency among various System V's about what
+ the name of this field is. */
+#define U_FPSTATE(u) u.u_fps.u_fpstate
+
+/* TIOCGETC is defined in System V 3.2 termio.h, but struct tchars
+ is not. This makes problems for inflow.c. */
+#define TIOCGETC_BROKEN
diff --git a/gnu/usr.bin/gdb/config/m-i386.h b/gnu/usr.bin/gdb/config/m-i386.h
new file mode 100644
index 0000000..5449ec4
--- /dev/null
+++ b/gnu/usr.bin/gdb/config/m-i386.h
@@ -0,0 +1,394 @@
+/* Macro defintions for i386.
+ 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. */
+
+/* Define the bit, byte, and word ordering of the machine. */
+/* #define BITS_BIG_ENDIAN */
+/* #define BYTES_BIG_ENDIAN */
+/* #define WORDS_BIG_ENDIAN */
+
+/*
+ * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu)
+ * July 1988
+ */
+
+
+#ifndef i386
+#define i386
+#endif
+
+/* I'm running gdb 3.4 under 386/ix 2.0.2, which is a derivative of AT&T's
+Sys V/386 3.2.
+
+On some machines, gdb crashes when it's starting up while calling the
+vendor's termio tgetent() routine. It always works when run under
+itself (actually, under 3.2, it's not an infinitely recursive bug.)
+After some poking around, it appears that depending on the environment
+size, or whether you're running YP, or the phase of the moon or something,
+the stack is not always long-aligned when main() is called, and tgetent()
+takes strong offense at that. On some machines this bug never appears, but
+on those where it does, it occurs quite reliably. */
+#define ALIGN_STACK_ON_STARTUP
+
+/* define USG if you are using sys5 /usr/include's */
+#define USG
+
+/* USG systems need these */
+#define vfork() fork()
+#define MAXPATHLEN 500
+
+/* define this if you don't have the extension to coff that allows
+ * file names to appear in the string table
+ * (aux.x_file.x_foff)
+ */
+#define COFF_NO_LONG_FILE_NAMES
+
+/* turn this on when rest of gdb is ready */
+/* #define IEEE_FLOAT */
+
+#define NBPG NBPC
+#define UPAGES USIZE
+
+#define HAVE_TERMIO
+
+/* Get rid of any system-imposed stack limit if possible. */
+
+/* #define SET_STACK_LIMIT_HUGE not in sys5 */
+
+/* Define this if the C compiler puts an underscore at the front
+ of external names before giving them to the linker. */
+
+/* #define NAMES_HAVE_UNDERSCORE */
+
+/* Specify debugger information format. */
+
+/* #define READ_DBX_FORMAT */
+#define COFF_FORMAT
+
+/* 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.
+ */
+#define START_INFERIOR_TRAPS_EXPECTED 4
+
+/* 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));}
+
+/* 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))
+
+/* This is the amount to subtract from u.u_ar0
+ to get the offset in the core file of the register values. */
+
+#define KERNEL_U_ADDR 0xe0000000
+
+/* Address of end of stack space. */
+
+#define STACK_END_ADDR 0x80000000
+
+/* 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. */
+
+#define DECR_PC_AFTER_BREAK 1
+
+/* 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)
+
+/* code to execute to print interesting information about the
+ * floating point processor (if any)
+ * No need to define if there is nothing to do.
+ */
+#define FLOAT_INFO { i386_float_info (); }
+
+
+/* Largest integer type */
+#define LONGEST long
+
+/* Name of the builtin type for the LONGEST type above. */
+#define BUILTIN_TYPE_LONGEST builtin_type_long
+
+/* Say how long (ordinary) registers are. */
+
+#define REGISTER_TYPE long
+
+/* 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
+
+#define REGISTER_U_ADDR(addr, blockend, regno) \
+ (addr) = i386_register_u_addr ((blockend),(regno));
+
+/* 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
+
+/* Nonzero if register N requires conversion
+ from raw format to virtual format. */
+
+#define REGISTER_CONVERTIBLE(N) (0)
+
+/* Convert data from raw format for register REGNUM
+ to virtual format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) {bcopy ((FROM), (TO), 4);}
+
+/* Convert data from virtual format for register REGNUM
+ to raw format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) {bcopy ((FROM), (TO), 4);}
+
+/* Return the GDB type object for the "standard" data type
+ of data in register N. */
+
+#define REGISTER_VIRTUAL_TYPE(N) (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), &(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) \
+ bcopy (REGBUF, VALBUF, 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.
+
+ FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address
+ and produces the nominal address of the caller frame.
+
+ However, if FRAME_CHAIN_VALID returns zero,
+ it means the given frame is the outermost one and has no caller.
+ In that case, FRAME_CHAIN_COMBINE is not used. */
+
+#define FRAME_CHAIN(thisframe) \
+ (outside_startup_file ((thisframe)->pc) ? \
+ read_memory_integer ((thisframe)->frame, 4) :\
+ 0)
+
+#define FRAME_CHAIN_VALID(chain, thisframe) \
+ (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe))))
+
+#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
+
+/* 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_LOOK_FOR_PROLOGUE(FI, FRAMELESS)
+
+#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) = i386_frame_num_args(fi)
+
+/* 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)); }
+
+
+/* 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 (); }
+
+/* Discard from the stack the innermost frame, restoring all registers. */
+
+#define POP_FRAME { i386_pop_frame (); }
+
+/* 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 */
+
+/* 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, type) \
+{ \
+ int from, to, delta, loc; \
+ loc = (int)(read_register (SP_REGNUM) - CALL_DUMMY_LENGTH); \
+ from = loc + 5; \
+ to = (int)(fun); \
+ delta = to - from; \
+ *(int *)((char *)(dummyname) + 1) = delta; \
+}
+
+
+#if 0
+/* Interface definitions for kernel debugger KDB. */
+
+/* Map machine fault codes into signal numbers.
+ First subtract 0, divide by 4, then index in a table.
+ Faults for which the entry in this table is 0
+ are not handled by KDB; the program's own trap handler
+ gets to handle then. */
+
+#define FAULT_CODE_ORIGIN 0
+#define FAULT_CODE_UNITS 4
+#define FAULT_TABLE \
+{ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0}
+
+/* Start running with a stack stretching from BEG to END.
+ BEG and END should be symbols meaningful to the assembler.
+ This is used only for kdb. */
+
+#define INIT_STACK(beg, end) {}
+
+/* Push the frame pointer register on the stack. */
+#define PUSH_FRAME_PTR {}
+
+/* Copy the top-of-stack to the frame pointer register. */
+#define POP_FRAME_PTR {}
+
+/* After KDB is entered by a fault, push all registers
+ that GDB thinks about (all NUM_REGS of them),
+ so that they appear in order of ascending GDB register number.
+ The fault code will be on the stack beyond the last register. */
+
+#define PUSH_REGISTERS {}
+
+/* Assuming the registers (including processor status) have been
+ pushed on the stack in order of ascending GDB register number,
+ restore them and return to the address in the saved PC register. */
+
+#define POP_REGISTERS {}
+#endif
diff --git a/gnu/usr.bin/gdb/config/m-i386bsd.h b/gnu/usr.bin/gdb/config/m-i386bsd.h
new file mode 100644
index 0000000..15d97b2
--- /dev/null
+++ b/gnu/usr.bin/gdb/config/m-i386bsd.h
@@ -0,0 +1,375 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1991 by William Jolitz at UUNET Technologies, Inc.
+ *
+ * @(#)m-i386bsd.h 6.7 (Berkeley) 5/8/91
+ */
+
+/* Macro definitions for i386.
+ 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. */
+
+/* Define the bit, byte, and word ordering of the machine. */
+/* #define BITS_BIG_ENDIAN */
+/* #define BYTES_BIG_ENDIAN */
+/* #define WORDS_BIG_ENDIAN */
+
+/*
+ * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu)
+ * July 1988
+ * [ MODIFIED FOR 386BSD W. Jolitz ]
+ */
+
+#ifndef i386
+#define i386 1
+#define i386b 1
+#endif
+
+#define IEEE_FLOAT
+#define LONG_LONG
+
+/* Library stuff: POSIX tty (not supported yet), V7 tty (sigh), vprintf. */
+
+#define HAVE_TERMIOS 1
+#define USE_OLD_TTY 1
+#define HAVE_VPRINTF 1
+
+/* We support local and remote kernel debugging. */
+
+#define KERNELDEBUG 1
+
+/* Get rid of any system-imposed stack limit if possible. */
+
+#define SET_STACK_LIMIT_HUGE
+
+/* Define this if the C compiler puts an underscore at the front
+ of external names before giving them to the linker. */
+
+#define NAMES_HAVE_UNDERSCORE
+
+/* Specify debugger information format. */
+
+#define READ_DBX_FORMAT
+
+/* 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.
+ */
+#define START_INFERIOR_TRAPS_EXPECTED 2
+
+/* 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));}
+
+/* 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))
+
+/* This is the amount to subtract from u.u_ar0
+ to get the offset in the core file of the register values. */
+
+#ifdef NEWVM
+#include <machine/vmparam.h>
+#define KERNEL_U_ADDR USRSTACK
+#else
+#define KERNEL_U_ADDR 0xfdffd000
+#endif
+
+/* Address of end of stack space. */
+
+#define STACK_END_ADDR KERNEL_U_ADDR
+
+/* 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. */
+
+#define DECR_PC_AFTER_BREAK 1
+
+/* Nonzero if instruction at PC is a return instruction. */
+
+#define ABOUT_TO_RETURN(pc) \
+ strchr("\302\303\312\313\317", read_memory_integer(pc, 1))
+
+/* 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)
+
+/* code to execute to print interesting information about the
+ * floating point processor (if any)
+ * No need to define if there is nothing to do.
+ */
+#define FLOAT_INFO { i386_float_info (); }
+
+
+/* Largest integer type */
+#define LONGEST long long
+
+/* Name of the builtin type for the LONGEST type above. */
+#define BUILTIN_TYPE_LONGEST builtin_type_long_long
+
+/* Say how long (ordinary) registers are. */
+
+#define REGISTER_TYPE long
+
+/* 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
+
+#define REGISTER_U_ADDR(addr, blockend, regno) \
+ (addr) = i386_register_u_addr ((blockend),(regno));
+
+/* 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
+
+/* Nonzero if register N requires conversion
+ from raw format to virtual format. */
+
+#define REGISTER_CONVERTIBLE(N) (0)
+
+/* Convert data from raw format for register REGNUM
+ to virtual format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) {bcopy ((FROM), (TO), 4);}
+
+/* Convert data from virtual format for register REGNUM
+ to raw format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) {bcopy ((FROM), (TO), 4);}
+
+/* Return the GDB type object for the "standard" data type
+ of data in register N. */
+
+#define REGISTER_VIRTUAL_TYPE(N) (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), &(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) \
+ bcopy (REGBUF, VALBUF, 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.
+
+ FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address
+ and produces the nominal address of the caller frame.
+
+ However, if FRAME_CHAIN_VALID returns zero,
+ it means the given frame is the outermost one and has no caller.
+ In that case, FRAME_CHAIN_COMBINE is not used. */
+
+#define FRAME_CHAIN(thisframe) \
+ (outside_startup_file ((thisframe)->pc) ? \
+ read_memory_integer ((thisframe)->frame, 4) :\
+ 0)
+
+#ifdef KERNELDEBUG
+#define KERNTEXT_BASE 0xfe000000
+#ifdef NEWVM
+#define KERNSTACK_TOP (read_register(SP_REGNUM) + 0x2000) /* approximate */
+#else
+/* #define KERNSTACK_TOP (P1PAGES << PGSHIFT) */
+#define KERNSTACK_TOP 0xfe000000
+#endif
+extern int kernel_debugging;
+#define FRAME_CHAIN_VALID(chain, thisframe) \
+ (chain != 0 && \
+ !kernel_debugging ? outside_startup_file(FRAME_SAVED_PC(thisframe)) :\
+ (chain >= read_register(SP_REGNUM) && chain < KERNSTACK_TOP))
+#else
+#define FRAME_CHAIN_VALID(chain, thisframe) \
+ (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe))))
+#endif
+
+#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
+
+/* 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_LOOK_FOR_PROLOGUE(FI, FRAMELESS)
+
+#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) = i386_frame_num_args(fi)
+
+/* 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)); }
+
+
+/* Discard from the stack the innermost frame, restoring all registers. */
+
+#define POP_FRAME { i386_pop_frame (); }
+
+#define NEW_CALL_FUNCTION
+
+#if 0
+/* Interface definitions for kernel debugger KDB. */
+
+/* Map machine fault codes into signal numbers.
+ First subtract 0, divide by 4, then index in a table.
+ Faults for which the entry in this table is 0
+ are not handled by KDB; the program's own trap handler
+ gets to handle then. */
+
+#define FAULT_CODE_ORIGIN 0
+#define FAULT_CODE_UNITS 4
+#define FAULT_TABLE \
+{ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0}
+
+/* Start running with a stack stretching from BEG to END.
+ BEG and END should be symbols meaningful to the assembler.
+ This is used only for kdb. */
+
+#define INIT_STACK(beg, end) {}
+
+/* Push the frame pointer register on the stack. */
+#define PUSH_FRAME_PTR {}
+
+/* Copy the top-of-stack to the frame pointer register. */
+#define POP_FRAME_PTR {}
+
+/* After KDB is entered by a fault, push all registers
+ that GDB thinks about (all NUM_REGS of them),
+ so that they appear in order of ascending GDB register number.
+ The fault code will be on the stack beyond the last register. */
+
+#define PUSH_REGISTERS {}
+
+/* Assuming the registers (including processor status) have been
+ pushed on the stack in order of ascending GDB register number,
+ restore them and return to the address in the saved PC register. */
+
+#define POP_REGISTERS {}
+#endif
diff --git a/gnu/usr.bin/gdb/config/m-i386g-sv32.h b/gnu/usr.bin/gdb/config/m-i386g-sv32.h
new file mode 100644
index 0000000..3d69eea
--- /dev/null
+++ b/gnu/usr.bin/gdb/config/m-i386g-sv32.h
@@ -0,0 +1,28 @@
+/* Macro defintions for i386, running System V 3.2.
+ Copyright (C) 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. */
+
+#include "m-i386gas.h"
+
+/* Apparently there is inconsistency among various System V's about what
+ the name of this field is. */
+#define U_FPSTATE(u) u.u_fps.u_fpstate
+
+/* TIOCGETC is defined in System V 3.2 termio.h, but struct tchars
+ is not. This makes problems for inflow.c. */
+#define TIOCGETC_BROKEN
diff --git a/gnu/usr.bin/gdb/config/m-i386gas.h b/gnu/usr.bin/gdb/config/m-i386gas.h
new file mode 100644
index 0000000..fbd2138
--- /dev/null
+++ b/gnu/usr.bin/gdb/config/m-i386gas.h
@@ -0,0 +1,37 @@
+/* Macro definitions for i386 using the GNU object file format.
+ 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. */
+
+/*
+ * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu)
+ * July 1988
+ *
+ * i386gnu: COFF_ENCAPSULATE
+ */
+
+
+#define COFF_ENCAPSULATE
+
+#include "m-i386.h"
+
+
+#define NAMES_HAVE_UNDERSCORE
+
+#undef COFF_FORMAT
+#define READ_DBX_FORMAT
+
diff --git a/gnu/usr.bin/gdb/copying.c b/gnu/usr.bin/gdb/copying.c
new file mode 100644
index 0000000..b3d7519
--- /dev/null
+++ b/gnu/usr.bin/gdb/copying.c
@@ -0,0 +1,215 @@
+/* Do not modify this file; it is created automatically
+ by copying.awk. */
+extern int immediate_quit;
+static void
+copying_info ()
+{
+ immediate_quit++;
+ printf_filtered ("\n");
+ printf_filtered (" GNU GENERAL PUBLIC LICENSE\n");
+ printf_filtered (" Version 1, February 1989\n");
+ printf_filtered ("\n");
+ printf_filtered (" Copyright (C) 1989 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 license agreements of most software companies try to keep users\n");
+ printf_filtered ("at the mercy of those companies. By contrast, our 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. The\n");
+ printf_filtered ("General Public License applies to the Free Software Foundation's\n");
+ printf_filtered ("software and to any other program whose authors commit to using it.\n");
+ printf_filtered ("You can use it for 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. Specifically, the General Public License is designed to make\n");
+ printf_filtered ("sure that you have the freedom to give away or sell copies of free\n");
+ printf_filtered ("software, that you receive source code or can get it if you want it,\n");
+ printf_filtered ("that you can change the software or use pieces of it in new free\n");
+ printf_filtered ("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 a 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 tell them their 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 (" 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 Agreement applies to any program or other work which\n");
+ printf_filtered ("contains a notice placed by the copyright holder saying it may be\n");
+ printf_filtered ("distributed under the terms of this General Public License. The\n");
+ printf_filtered ("\"Program\", below, refers to any such program or work, and a \"work based\n");
+ printf_filtered ("on the Program\" means either the Program or any work containing the\n");
+ printf_filtered ("Program or a portion of it, either verbatim or with modifications. Each\n");
+ printf_filtered ("licensee is addressed as \"you\".\n");
+ printf_filtered ("\n");
+ printf_filtered (" 1. You may copy and distribute verbatim copies of the Program's source\n");
+ printf_filtered ("code as you receive it, in any medium, provided that you conspicuously and\n");
+ printf_filtered ("appropriately publish on each copy an appropriate copyright notice and\n");
+ printf_filtered ("disclaimer of warranty; keep intact all the notices that refer to this\n");
+ printf_filtered ("General Public License and to the absence of any warranty; and give any\n");
+ printf_filtered ("other recipients of the Program a copy of this General Public License\n");
+ printf_filtered ("along with the Program. You may charge a fee for the physical act of\n");
+ printf_filtered ("transferring a copy.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 2. You may modify your copy or copies of the Program or any portion of\n");
+ printf_filtered ("it, and copy and distribute such modifications under the terms of Paragraph\n");
+ printf_filtered ("1 above, provided that you also do the following:\n");
+ printf_filtered ("\n");
+ printf_filtered (" a) cause the modified files to carry prominent notices stating that\n");
+ printf_filtered (" you changed the files and the date of any change; and\n");
+ printf_filtered ("\n");
+ printf_filtered (" b) cause the whole of any work that you distribute or publish, that\n");
+ printf_filtered (" in whole or in part contains the Program or any part thereof, either\n");
+ printf_filtered (" with or without modifications, to be licensed at no charge to all\n");
+ printf_filtered (" third parties under the terms of this General Public License (except\n");
+ printf_filtered (" that you may choose to grant warranty protection to some or all\n");
+ printf_filtered (" third parties, at your option).\n");
+ printf_filtered ("\n");
+ printf_filtered (" c) If the modified program normally reads commands interactively when\n");
+ printf_filtered (" run, you must cause it, when started running for such interactive use\n");
+ printf_filtered (" in the simplest and most usual way, to print or display an\n");
+ printf_filtered (" announcement including an appropriate copyright notice and a notice\n");
+ printf_filtered (" that there is no warranty (or else, saying that you provide a\n");
+ printf_filtered (" warranty) and that users may redistribute the program under these\n");
+ printf_filtered (" conditions, and telling the user how to view a copy of this General\n");
+ printf_filtered (" Public License.\n");
+ printf_filtered ("\n");
+ printf_filtered (" d) You may charge a fee for the physical act of transferring a\n");
+ printf_filtered (" copy, and you may at your option offer warranty protection in\n");
+ printf_filtered (" exchange for a fee.\n");
+ printf_filtered ("\n");
+ printf_filtered ("Mere aggregation of another independent work with the Program (or its\n");
+ printf_filtered ("derivative) on a volume of a storage or distribution medium does not bring\n");
+ printf_filtered ("the other work under the scope of these terms.\n");
+ printf_filtered (" \n");
+ printf_filtered (" 3. You may copy and distribute the Program (or a portion or derivative of\n");
+ printf_filtered ("it, under Paragraph 2) in object code or executable form under the terms of\n");
+ printf_filtered ("Paragraphs 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\n");
+ printf_filtered (" Paragraphs 1 and 2 above; 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 free (except for a nominal charge\n");
+ printf_filtered (" for the cost of distribution) a complete machine-readable copy of the\n");
+ printf_filtered (" corresponding source code, to be distributed under the terms of\n");
+ printf_filtered (" Paragraphs 1 and 2 above; or,\n");
+ printf_filtered ("\n");
+ printf_filtered (" c) accompany it with the information you received as to where the\n");
+ printf_filtered (" corresponding source code may be obtained. (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 alone.)\n");
+ printf_filtered ("\n");
+ printf_filtered ("Source code for a work means the preferred form of the work for making\n");
+ printf_filtered ("modifications to it. For an executable file, complete source code means\n");
+ printf_filtered ("all the source code for all modules it contains; but, as a special\n");
+ printf_filtered ("exception, it need not include source code for modules which are standard\n");
+ printf_filtered ("libraries that accompany the operating system on which the executable\n");
+ printf_filtered ("file runs, or for standard header files or definitions files that\n");
+ printf_filtered ("accompany that operating system.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 4. You may not copy, modify, sublicense, distribute or transfer the\n");
+ printf_filtered ("Program except as expressly provided under this General Public License.\n");
+ printf_filtered ("Any attempt otherwise to copy, modify, sublicense, distribute or transfer\n");
+ printf_filtered ("the Program is void, and will automatically terminate your rights to use\n");
+ printf_filtered ("the Program under this License. However, parties who have received\n");
+ printf_filtered ("copies, or rights to use copies, from you under this General Public\n");
+ printf_filtered ("License will not have their licenses terminated so long as such parties\n");
+ printf_filtered ("remain in full compliance.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 5. By copying, distributing or modifying the Program (or any work based\n");
+ printf_filtered ("on the Program) you indicate your acceptance of this license to do so,\n");
+ printf_filtered ("and all its terms and conditions.\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 original\n");
+ printf_filtered ("licensor to copy, distribute or modify the Program subject to these\n");
+ printf_filtered ("terms and conditions. You may not impose any further restrictions on the\n");
+ printf_filtered ("recipients' exercise of the rights granted herein.\n");
+ printf_filtered (" \n");
+ printf_filtered (" 7. 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 the 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 ("the license, you may choose any version ever published by the Free Software\n");
+ printf_filtered ("Foundation.\n");
+ printf_filtered ("\n");
+ printf_filtered (" 8. 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
+warranty_info ()
+{
+ immediate_quit++;
+ printf_filtered (" NO WARRANTY\n");
+ printf_filtered ("\n");
+ printf_filtered (" 9. 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 (" 10. 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_info ("copying", copying_info,
+ "Conditions for redistributing copies of GDB.");
+ add_info ("warranty", warranty_info,
+ "Various kinds of warranty you do not have.");
+}
diff --git a/gnu/usr.bin/gdb/core.c b/gnu/usr.bin/gdb/core.c
new file mode 100644
index 0000000..307addb
--- /dev/null
+++ b/gnu/usr.bin/gdb/core.c
@@ -0,0 +1,581 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)core.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Work with core dump and executable files, for GDB.
+ 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. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h" /* required by inferior.h */
+#include "inferior.h"
+
+#ifdef USG
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#else
+#include <a.out.h>
+#endif
+#ifndef N_MAGIC
+#ifdef COFF_FORMAT
+#define N_MAGIC(exec) ((exec).magic)
+#else
+#define N_MAGIC(exec) ((exec).a_magic)
+#endif
+#endif
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#ifdef UMAX_CORE
+#include <sys/ptrace.h>
+#else
+#include <sys/user.h>
+#endif
+
+#ifndef N_TXTADDR
+#define N_TXTADDR(hdr) 0
+#endif /* no N_TXTADDR */
+
+#ifndef N_DATADDR
+#define N_DATADDR(hdr) hdr.a_text
+#endif /* no N_DATADDR */
+
+#ifndef COFF_FORMAT
+#ifndef AOUTHDR
+#define AOUTHDR struct exec
+#endif
+#endif
+
+extern char *sys_siglist[];
+
+extern core_file_command (), exec_file_command ();
+
+/* Hook for `exec_file_command' command to call. */
+
+void (*exec_file_display_hook) ();
+
+/* File names of core file and executable file. */
+
+char *corefile;
+char *execfile;
+
+/* Descriptors on which core file and executable file are open.
+ Note that the execchan is closed when an inferior is created
+ and reopened if the inferior dies or is killed. */
+
+int corechan;
+int execchan;
+
+/* Last modification time of executable file.
+ Also used in source.c to compare against mtime of a source file. */
+
+int exec_mtime;
+
+/* Virtual addresses of bounds of the two areas of memory in the core file. */
+
+CORE_ADDR data_start;
+CORE_ADDR data_end;
+CORE_ADDR stack_start;
+CORE_ADDR stack_end;
+
+#if defined (REG_STACK_SEGMENT)
+/* Start and end of the register stack segment. */
+CORE_ADDR reg_stack_start;
+CORE_ADDR reg_stack_end;
+#endif /* REG_STACK_SEGMENT */
+
+/* Virtual addresses of bounds of two areas of memory in the exec file.
+ Note that the data area in the exec file is used only when there is no core file. */
+
+CORE_ADDR text_start;
+CORE_ADDR text_end;
+
+CORE_ADDR exec_data_start;
+CORE_ADDR exec_data_end;
+
+/* Offset within executable file of start of text area data. */
+
+int text_offset;
+
+/* Offset within executable file of start of data area data. */
+
+int exec_data_offset;
+
+/* Offset within core file of start of data area data. */
+
+int data_offset;
+
+/* Offset within core file of start of stack area data. */
+
+int stack_offset;
+
+#ifdef COFF_FORMAT
+/* various coff data structures */
+
+FILHDR file_hdr;
+SCNHDR text_hdr;
+SCNHDR data_hdr;
+
+#endif /* not COFF_FORMAT */
+
+/* a.out header saved in core file. */
+
+AOUTHDR core_aouthdr;
+
+/* a.out header of exec file. */
+
+AOUTHDR exec_aouthdr;
+
+void validate_files ();
+unsigned int register_addr ();
+
+/* 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) ();
+{
+ 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 ()
+{
+ if (execchan >= 0)
+ close (execchan);
+ execchan = -1;
+}
+
+void
+reopen_exec_file ()
+{
+ if (execchan < 0 && execfile != 0)
+ {
+ char *filename = concat (execfile, "", "");
+ exec_file_command (filename, 0);
+ free (filename);
+ }
+}
+
+/* If we have both a core file and an exec file,
+ print a warning if they don't go together.
+ This should really check that the core file came
+ from that exec file, but I don't know how to do it. */
+
+void
+validate_files ()
+{
+ if (execfile != 0 && corefile != 0)
+ {
+ struct stat st_core;
+
+ if (fstat (corechan, &st_core) < 0)
+ /* It might be a good idea to print an error message.
+ On the other hand, if the user tries to *do* anything with
+ the core file, (s)he'll find out soon enough. */
+ return;
+
+ if (N_MAGIC (core_aouthdr) != 0
+ && bcmp (&core_aouthdr, &exec_aouthdr, sizeof core_aouthdr))
+ printf ("Warning: core file does not match specified executable file.\n");
+ else if (exec_mtime > st_core.st_mtime) {
+#ifdef KERNELDEBUG
+ extern int kernel_debugging;
+ if (!kernel_debugging)
+#endif
+ printf ("Warning: exec file is newer than core file.\n");
+ }
+ }
+}
+
+/* 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 (err && execfile == 0)
+ error ("No executable file specified.\n\
+Use the \"exec-file\" and \"symbol-file\" commands.");
+ return execfile;
+}
+
+int
+have_core_file_p ()
+{
+ return corefile != 0;
+}
+
+static void
+files_info ()
+{
+ char *symfile;
+ extern char *get_sym_file ();
+
+ if (execfile)
+ printf ("Executable file \"%s\".\n", execfile);
+ else
+ printf ("No executable file\n");
+ if (corefile == 0)
+ printf ("No core dump file\n");
+ else
+ printf ("Core dump file \"%s\".\n", corefile);
+
+ if (have_inferior_p ())
+ printf ("Using the running image of the program, rather than these files.\n");
+
+ symfile = get_sym_file ();
+ if (symfile != 0)
+ printf ("Symbols from \"%s\".\n", symfile);
+
+#ifdef FILES_INFO_HOOK
+ if (FILES_INFO_HOOK ())
+ return;
+#endif
+
+ if (! have_inferior_p ())
+ {
+ if (execfile)
+ {
+ printf ("Text segment in executable from 0x%x to 0x%x.\n",
+ text_start, text_end);
+ printf ("Data segment in executable from 0x%x to 0x%x.\n",
+ exec_data_start, exec_data_end);
+ if (corefile)
+ printf ("(But since we have a core file, we're using...)\n");
+ }
+ if (corefile)
+ {
+ printf ("Data segment in core file from 0x%x to 0x%x.\n",
+ data_start, data_end);
+ printf ("Stack segment in core file from 0x%x to 0x%x.\n",
+ stack_start, stack_end);
+ }
+ }
+}
+
+/* Read "memory data" from core file and/or executable file.
+ Returns zero if successful, 1 if xfer_core_file failed, errno value if
+ ptrace failed. */
+
+int
+read_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ if (len == 0)
+ return 0;
+
+ if (have_inferior_p ())
+ {
+ if (remote_debugging)
+ return remote_read_inferior_memory (memaddr, myaddr, len);
+ else
+ return read_inferior_memory (memaddr, myaddr, len);
+ }
+ else
+ return xfer_core_file (memaddr, myaddr, len);
+}
+
+/* Write LEN bytes of data starting at address MYADDR
+ into debugged program memory at address MEMADDR.
+ Returns zero if successful, or an errno value if ptrace failed. */
+
+int
+write_memory (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ if (have_inferior_p ())
+ {
+ if (remote_debugging)
+ return remote_write_inferior_memory (memaddr, myaddr, len);
+ else
+ return write_inferior_memory (memaddr, myaddr, len);
+ }
+ else
+ error ("Can write memory only when program being debugged is running.");
+}
+
+#ifndef XFER_CORE_FILE
+int (*core_file_hook)(); /* hook to handle special core files like
+ like /dev/mem and crash dumps */
+
+/* Read from the program's memory (except for inferior processes).
+ This function is misnamed, since it only reads, never writes; and
+ since it will use the core file and/or executable file as necessary.
+
+ It should be extended to write as well as read, FIXME, for patching files.
+
+ Return 0 if address could be read, 1 if not. */
+
+int
+xfer_core_file (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ register int i;
+ register int val;
+ int xferchan;
+ char **xferfile;
+ int fileptr;
+ int returnval = 0;
+
+ if (core_file_hook)
+ return ((*core_file_hook)(memaddr, myaddr, len));
+
+ while (len > 0)
+ {
+ xferfile = 0;
+ xferchan = 0;
+
+ /* Determine which file the next bunch of addresses reside in,
+ and where in the file. Set the file's read/write pointer
+ to point at the proper place for the desired address
+ and set xferfile and xferchan for the correct file.
+
+ If desired address is nonexistent, leave them zero.
+
+ i is set to the number of bytes that can be handled
+ along with the next address.
+
+ We put the most likely tests first for efficiency. */
+
+ /* Note that if there is no core file
+ data_start and data_end are equal. */
+ if (memaddr >= data_start && memaddr < data_end)
+ {
+ i = min (len, data_end - memaddr);
+ fileptr = memaddr - data_start + data_offset;
+ xferfile = &corefile;
+ xferchan = corechan;
+ }
+ /* Note that if there is no core file
+ stack_start and stack_end are equal. */
+ else if (memaddr >= stack_start && memaddr < stack_end)
+ {
+ i = min (len, stack_end - memaddr);
+ fileptr = memaddr - stack_start + stack_offset;
+ xferfile = &corefile;
+ xferchan = corechan;
+ }
+#ifdef REG_STACK_SEGMENT
+ /* Pyramids have an extra segment in the virtual address space
+ for the (control) stack of register-window frames */
+ 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;
+ xferfile = &corefile;
+ xferchan = corechan;
+ }
+#endif /* REG_STACK_SEGMENT */
+
+ else if (corechan < 0
+ && memaddr >= exec_data_start && memaddr < exec_data_end)
+ {
+ i = min (len, exec_data_end - memaddr);
+ fileptr = memaddr - exec_data_start + exec_data_offset;
+ xferfile = &execfile;
+ xferchan = execchan;
+ }
+ else if (memaddr >= text_start && memaddr < text_end)
+ {
+ i = min (len, text_end - memaddr);
+ fileptr = memaddr - text_start + text_offset;
+ xferfile = &execfile;
+ xferchan = execchan;
+ }
+ else if (memaddr < text_start)
+ {
+ i = min (len, text_start - memaddr);
+ }
+ else if (memaddr >= text_end
+ && memaddr < (corechan >= 0? data_start : exec_data_start))
+ {
+ i = min (len, data_start - memaddr);
+ }
+ else if (corechan >= 0
+ && memaddr >= data_end && memaddr < stack_start)
+ {
+ i = min (len, stack_start - memaddr);
+ }
+ else if (corechan < 0 && memaddr >= exec_data_end)
+ {
+ /* Since there is nothing at higher addresses than data
+ (without a core file or an inferior, there is no
+ stack, set i to do the rest of the operation now. */
+ i = len;
+ }
+#ifdef REG_STACK_SEGMENT
+ else if (memaddr >= reg_stack_end && reg_stack_end != 0)
+ {
+ i = min (len, reg_stack_start - memaddr);
+ }
+ else if (memaddr >= stack_end && memaddr < reg_stack_start)
+#else /* no REG_STACK_SEGMENT. */
+ else if (memaddr >= stack_end && stack_end != 0)
+#endif /* no REG_STACK_SEGMENT. */
+ {
+ /* Since there is nothing at higher addresses than
+ the stack, set i to do the rest of the operation now. */
+ i = len;
+ }
+ else
+ {
+ /* Address did not classify into one of the known ranges.
+ This shouldn't happen; we catch the endpoints. */
+ fatal ("Internal: Bad case logic in xfer_core_file.");
+ }
+
+ /* Now we know which file to use.
+ Set up its pointer and transfer the data. */
+ if (xferfile)
+ {
+ if (*xferfile == 0)
+ if (xferfile == &execfile)
+ error ("No program file to examine.");
+ else
+ error ("No core dump file or running program to examine.");
+ val = lseek (xferchan, fileptr, 0);
+ if (val == -1)
+ perror_with_name (*xferfile);
+ val = myread (xferchan, myaddr, i);
+ if (val < 0)
+ perror_with_name (*xferfile);
+ }
+ /* If this address is for nonexistent memory,
+ read zeros if reading, or do nothing if writing.
+ Actually, we never right. */
+ else
+ {
+ bzero (myaddr, i);
+ returnval = 1;
+ }
+
+ memaddr += i;
+ myaddr += i;
+ len -= i;
+ }
+ return returnval;
+}
+#endif /* XFER_CORE_FILE */
+
+/* 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;
+}
+
+#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 >= NUM_REGS)
+ error ("Invalid register number %d.", regno);
+
+ REGISTER_U_ADDR (addr, blockend, regno);
+
+ return addr;
+}
+
+#endif /* REGISTER_U_ADDR */
+
+void
+_initialize_core()
+{
+ corechan = -1;
+ execchan = -1;
+ corefile = 0;
+ execfile = 0;
+ exec_file_display_hook = 0;
+
+ text_start = 0;
+ text_end = 0;
+ data_start = 0;
+ data_end = 0;
+ exec_data_start = 0;
+ exec_data_end = 0;
+ stack_start = STACK_END_ADDR;
+ stack_end = STACK_END_ADDR;
+
+ add_com ("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.");
+ add_com ("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.");
+ add_info ("files", files_info, "Names of files being debugged.");
+}
+
diff --git a/gnu/usr.bin/gdb/cplus-dem.c b/gnu/usr.bin/gdb/cplus-dem.c
new file mode 100644
index 0000000..8ea9c8b
--- /dev/null
+++ b/gnu/usr.bin/gdb/cplus-dem.c
@@ -0,0 +1,996 @@
+/* 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, int mode)
+
+ If NAME 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.
+
+ If MODE > 0, then ANSI qualifiers such as `const' and `void' are output.
+ Otherwise they are not.
+ If MODE >= 0, parameters are emitted; otherwise not.
+
+ For example,
+
+ cplus_demangle ("foo__1Ai", 0) => "A::foo(int)"
+ cplus_demangle ("foo__1Ai", 1) => "A::foo(int)"
+ cplus_demangle ("foo__1Ai", -1) => "A::foo"
+
+ cplus_demangle ("foo__1Afe", 0) => "A::foo(float,...)"
+ cplus_demangle ("foo__1Afe", 1) => "A::foo(float,...)"
+ cplus_demangle ("foo__1Afe", -1) => "A::foo"
+
+ 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, int mode);
+#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, int arg_mode);
+static int do_type (const char **type, string *result, int arg_mode);
+static int do_arg (const char **type, string *result, int arg_mode);
+static void munge_function_name (string *name, int arg_mode);
+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, arg_mode)
+ const char *type;
+ int arg_mode;
+{
+ 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
+
+# define print_ansi_qualifiers (arg_mode > 0)
+# define print_arg_types (arg_mode >= 0)
+
+ 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 "_vt$" */
+ 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, arg_mode);
+ }
+ 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, arg_mode);
+ if (const_flag && print_arg_types)
+ string_append (&decl, " const");
+ break;
+ case 'F':
+ p += 1;
+ success = do_args (&p, &decl, arg_mode);
+ 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, arg_mode)
+ const char **type;
+ string *result;
+ int arg_mode;
+{
+ 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, arg_mode) || **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, arg_mode)) || **type != '_')
+ {
+ success = 0;
+ break;
+ }
+ *type += 1;
+ if (! print_ansi_qualifiers)
+ break;
+ 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, "volatile");
+ }
+ break;
+ }
+
+ case 'C':
+ if ((*type)[1] == 'P')
+ {
+ *type += 1;
+ if (print_ansi_qualifiers)
+ {
+ 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 (print_ansi_qualifiers)
+ {
+ 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 (print_ansi_qualifiers)
+ {
+ 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, arg_mode)
+ const char **type;
+ string *result;
+ int arg_mode;
+{
+ const char *start = *type;
+
+ if (!do_type (type, result, arg_mode))
+ 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, arg_mode)
+ const char **type;
+ string *decl;
+ int arg_mode;
+{
+ string arg;
+ int need_comma = 0;
+
+ if (print_arg_types)
+ 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 && print_arg_types)
+ string_append (decl, ", ");
+ if (!do_arg (&tem, &arg, arg_mode))
+ return 0;
+ if (print_arg_types)
+ string_appends (decl, &arg);
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+ else
+ {
+ if (need_comma & print_arg_types)
+ string_append (decl, ", ");
+ if (!do_arg (type, &arg, arg_mode))
+ return 0;
+ if (print_arg_types)
+ string_appends (decl, &arg);
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+
+ if (**type == 'v')
+ *type += 1;
+ else if (**type == 'e')
+ {
+ *type += 1;
+ if (print_arg_types)
+ {
+ if (need_comma)
+ string_append (decl, ",");
+ string_append (decl, "...");
+ }
+ }
+
+ if (print_arg_types)
+ string_append (decl, ")");
+ return 1;
+}
+
+static void
+munge_function_name (name, arg_mode)
+ string *name;
+ int arg_mode;
+{
+ 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, arg_mode))
+ {
+ 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/gdb/dbxread.c b/gnu/usr.bin/gdb/dbxread.c
new file mode 100644
index 0000000..7a25665
--- /dev/null
+++ b/gnu/usr.bin/gdb/dbxread.c
@@ -0,0 +1,5727 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)dbxread.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Read dbx symbol tables and convert to internal format, for GDB.
+ Copyright (C) 1986, 1987, 1988, 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. */
+
+/* Symbol read-in occurs in two phases:
+ 1. A scan (read_dbx_symtab()) of the entire executable, whose sole
+ purpose is to make a list of symbols (partial symbol table)
+ which will cause symbols
+ to be read in if referenced. This scan happens when the
+ "symbol-file" command is given (symbol_file_command()).
+ 2. Full read-in of symbols. (psymtab_to_symtab()). This happens
+ when a symbol in a file for which symbols have not yet been
+ read in is referenced.
+ 2a. The "add-file" command. Similar to #2. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+
+#ifdef READ_DBX_FORMAT
+
+#ifdef USG
+#include <sys/types.h>
+#include <fcntl.h>
+#define L_SET 0
+#define L_INCR 1
+#endif
+
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#include "stab.gnu.h"
+#else
+#include <a.out.h>
+#include <stab.h>
+#endif
+#include <ctype.h>
+
+#ifndef NO_GNU_STABS
+/*
+ * Define specifically gnu symbols here.
+ */
+
+/* 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. */
+#ifndef N_INDR
+#define N_INDR 0xa
+#endif
+
+/* 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. */
+
+#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 N_WARNING
+#define N_WARNING 0x1E /* Warning message to print if file included */
+#endif /* This is input to ld */
+
+#ifndef __GNU_STAB__
+
+/* Line number for the data section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_DSLINE
+#define N_DSLINE (N_SLINE+N_DATA-N_TEXT)
+#endif
+
+/* Line number for the bss section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_BSLINE
+#define N_BSLINE (N_SLINE+N_BSS-N_TEXT)
+#endif
+
+#endif /* not __GNU_STAB__ */
+#endif /* NO_GNU_STABS */
+
+#include <obstack.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include "symtab.h"
+
+#ifndef COFF_FORMAT
+#ifndef AOUTHDR
+#define AOUTHDR struct exec
+#endif
+#endif
+
+static void add_symbol_to_list ();
+static void read_dbx_symtab ();
+static void process_one_symbol ();
+static void free_all_psymbols ();
+static struct type *read_type ();
+static struct type *read_range_type ();
+static struct type *read_enum_type ();
+static struct type *read_struct_type ();
+static struct type *read_array_type ();
+static long read_number ();
+static void read_huge_number ();
+static void finish_block ();
+static struct blockvector *make_blockvector ();
+static struct symbol *define_symbol ();
+static void start_subfile ();
+static int hashname ();
+static void hash_symsegs ();
+static struct pending *copy_pending ();
+static void fix_common_block ();
+
+static void add_undefined_type ();
+static void cleanup_undefined_types ();
+
+extern char *index();
+
+extern struct symtab *read_symsegs ();
+extern void free_all_symtabs ();
+extern void free_all_psymtabs ();
+extern void free_inclink_symtabs ();
+
+/* C++ */
+static struct type **read_args ();
+
+/* Macro to determine which symbols to ignore when reading the first symbol
+ of a file. Some machines override this definition. */
+#ifdef N_NSYMS
+#ifndef IGNORE_SYMBOL
+/* This code is used on Ultrix systems. Ignore it */
+#define IGNORE_SYMBOL(type) (type == N_NSYMS)
+#endif
+#else
+#ifndef IGNORE_SYMBOL
+/* Don't ignore any symbols. */
+#define IGNORE_SYMBOL(type) (0)
+#endif
+#endif /* not N_NSYMS */
+
+/* Macro for number of symbol table entries (in usual a.out format).
+ Some machines override this definition. */
+#ifndef NUMBER_OF_SYMBOLS
+#ifdef COFF_HEADER
+#define NUMBER_OF_SYMBOLS \
+ ((COFF_HEADER(hdr) ? hdr.coffhdr.filehdr.f_nsyms : hdr.a_syms) / \
+ sizeof (struct nlist))
+#else
+#define NUMBER_OF_SYMBOLS (hdr.a_syms / sizeof (struct nlist))
+#endif
+#endif
+
+/* Macro for file-offset of symbol table (in usual a.out format). */
+#ifndef SYMBOL_TABLE_OFFSET
+#define SYMBOL_TABLE_OFFSET N_SYMOFF (hdr)
+#endif
+
+/* Macro for file-offset of string table (in usual a.out format). */
+#ifndef STRING_TABLE_OFFSET
+#define STRING_TABLE_OFFSET (N_SYMOFF (hdr) + hdr.a_syms)
+#endif
+
+/* Macro to store the length of the string table data in INTO. */
+#ifndef READ_STRING_TABLE_SIZE
+#define READ_STRING_TABLE_SIZE(INTO) \
+{ val = myread (desc, &INTO, sizeof INTO); \
+ if (val < 0) perror_with_name (name); }
+#endif
+
+/* Macro to declare variables to hold the file's header data. */
+#ifndef DECLARE_FILE_HEADERS
+#define DECLARE_FILE_HEADERS AOUTHDR hdr
+#endif
+
+/* Macro to read the header data from descriptor DESC and validate it.
+ NAME is the file name, for error messages. */
+#ifndef READ_FILE_HEADERS
+#ifdef HEADER_SEEK_FD
+#define READ_FILE_HEADERS(DESC, NAME) \
+{ HEADER_SEEK_FD (DESC); \
+ val = myread (DESC, &hdr, sizeof hdr); \
+ if (val < 0) perror_with_name (NAME); \
+ if (N_BADMAG (hdr)) \
+ error ("File \"%s\" not in executable format.", NAME); }
+#else
+#define READ_FILE_HEADERS(DESC, NAME) \
+{ val = myread (DESC, &hdr, sizeof hdr); \
+ if (val < 0) perror_with_name (NAME); \
+ if (N_BADMAG (hdr)) \
+ error ("File \"%s\" not in executable format.", NAME); }
+#endif
+#endif
+
+/* Non-zero if this is an object (.o) file, rather than an executable.
+ Distinguishing between the two is rarely necessary (and seems like
+ a hack, but there is no other way to do ADDR_OF_TEXT_SEGMENT
+ right for SunOS). */
+#if !defined (IS_OBJECT_FILE)
+/* This will not work
+ if someone decides to make ld preserve relocation info. */
+#define IS_OBJECT_FILE (hdr.a_trsize != 0)
+#endif
+
+/* Macro for size of text segment */
+#ifndef SIZE_OF_TEXT_SEGMENT
+#define SIZE_OF_TEXT_SEGMENT hdr.a_text
+#endif
+
+/* Get the address in debugged memory of the start
+ of the text segment. */
+#if !defined (ADDR_OF_TEXT_SEGMENT)
+#if defined (N_TXTADDR)
+#define ADDR_OF_TEXT_SEGMENT (IS_OBJECT_FILE ? 0 : N_TXTADDR (hdr))
+#else /* no N_TXTADDR */
+#define ADDR_OF_TEXT_SEGMENT 0
+#endif /* no N_TXTADDR */
+#endif /* no ADDR_OF_TEXT_SEGMENT */
+
+/* Macro to get entry point from headers. */
+#ifndef ENTRY_POINT
+#define ENTRY_POINT hdr.a_entry
+#endif
+
+/* 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
+
+/* Convert stab register number (from `r' declaration) to a gdb REGNUM. */
+
+#ifndef STAB_REG_TO_REGNUM
+#define STAB_REG_TO_REGNUM(VALUE) (VALUE)
+#endif
+
+/* 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
+
+/* Nonzero means give verbose info on gdb action. From main.c. */
+extern int info_verbose;
+
+/* Chain of symtabs made from reading the file's symsegs.
+ These symtabs do not go into symtab_list themselves,
+ but the information is copied from them when appropriate
+ to make the symtabs that will exist permanently. */
+
+static struct symtab *symseg_chain;
+
+/* Symseg symbol table for the file whose data we are now processing.
+ It is one of those in symseg_chain. Or 0, for a compilation that
+ has no symseg. */
+
+static struct symtab *current_symseg;
+
+/* Name of source file whose symbol data we are now processing.
+ This comes from a symbol of type N_SO. */
+
+static char *last_source_file;
+
+/* Core address of start of text of current source file.
+ This too comes from the N_SO symbol. */
+
+static CORE_ADDR last_source_start_addr;
+
+/* End of the text segment of the executable file,
+ as found in the symbol _etext. */
+
+static CORE_ADDR end_of_text_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;
+ struct linetable *line_vector;
+ int line_vector_length;
+ int line_vector_index;
+ int prev_line_number;
+};
+
+static struct subfile *subfiles;
+
+static struct subfile *current_subfile;
+
+/* Count symbols as they are processed, for error messages. */
+
+static int symnum;
+
+/* Vector of types defined so far, indexed by their dbx type numbers.
+ (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.) */
+
+static struct typevector *type_vector;
+
+/* Number of elements allocated for type_vector currently. */
+
+static int type_vector_length;
+
+/* 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;
+
+/* Hash table of global symbols whose values are not known yet.
+ They are chained thru the SYMBOL_VALUE, 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. */
+
+#define HASHSIZE 127
+static struct symbol *global_sym_chain[HASHSIZE];
+
+/* 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. */
+struct pending *free_pendings;
+
+/* Here are the three lists that symbols are put on. */
+
+struct pending *file_symbols; /* static at top level, and types */
+
+struct pending *global_symbols; /* global functions and variables */
+
+struct pending *local_symbols; /* everything local to lexical context */
+
+/* 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. */
+
+struct pending *common_block;
+int common_block_i;
+
+/* Stack representing unclosed lexical contexts
+ (that will become blocks, eventually). */
+
+struct context_stack
+{
+ struct pending *locals;
+ struct pending_block *old_blocks;
+ struct symbol *name;
+ CORE_ADDR start_addr;
+ int depth;
+};
+
+struct context_stack *context_stack;
+
+/* Index of first unused entry in context stack. */
+int context_stack_depth;
+
+/* Currently allocated size of context stack. */
+
+int context_stack_size;
+
+/* Nonzero if within a function (so symbols should be local,
+ if nothing says specifically). */
+
+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;
+};
+
+struct pending_block *pending_blocks;
+
+extern CORE_ADDR startup_file_start; /* From blockframe.c */
+extern CORE_ADDR startup_file_end; /* From blockframe.c */
+
+/* File name symbols were loaded from. */
+
+static char *symfile;
+
+/* Low and high symbol values (inclusive) for the global variable
+ entries in the symbol file. */
+
+static int first_global_sym, last_global_sym;
+
+/* Structures with which to manage partial symbol allocation. */
+
+struct psymbol_allocation_list global_psymbols, static_psymbols;
+
+/* Global variable which, when set, indicates that we are processing a
+ .o file compiled with gcc */
+
+static unsigned char processing_gcc_compilation;
+
+/* Make a list of forward references which haven't been defined. */
+static struct type **undef_types;
+static int undef_types_allocated, undef_types_length;
+
+ /* Setup a define to deal cleanly with the underscore problem */
+
+#ifdef NAMES_HAVE_UNDERSCORE
+#define HASH_OFFSET 1
+#else
+#define HASH_OFFSET 0
+#endif
+
+#if 0
+/* I'm not sure why this is here. To debug bugs which cause
+ an infinite loop of allocations, I suppose. In any event,
+ dumping core when out of memory isn't usually right. */
+static int
+xxmalloc (n)
+{
+ int v = malloc (n);
+ if (v == 0)
+ {
+ fprintf (stderr, "Virtual memory exhausted.\n");
+ abort ();
+ }
+ return v;
+}
+#else /* not 0 */
+#define xxmalloc xmalloc
+#endif /* not 0 */
+
+/* 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. */
+
+static char *
+obsavestring (ptr, size)
+ char *ptr;
+ int size;
+{
+ register char *p = (char *) obstack_alloc (symbol_obstack, size + 1);
+ /* Open-coded bcopy--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. */
+
+static char *
+obconcat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
+ register char *val = (char *) obstack_alloc (symbol_obstack, len);
+ strcpy (val, s1);
+ strcat (val, s2);
+ strcat (val, s3);
+ return val;
+}
+
+/* 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
+{
+ char *name; /* Name of header file */
+ int instance; /* Numeric code distinguishing instances
+ of one header file that produced
+ different results when included.
+ It comes from the N_BINCL or N_EXCL. */
+ struct type **vector; /* Pointer to vector of types */
+ int length; /* Allocated length (# elts) of that vector */
+};
+
+static struct header_file *header_files;
+
+static int n_header_files;
+
+static int n_allocated_header_files;
+
+/* 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;
+
+/* 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. */
+
+static int *this_object_header_files;
+
+static int n_this_object_header_files;
+
+static int n_allocated_this_object_header_files;
+
+/* When a header file is getting special overriding definitions
+ for one source file, record here the header_files index
+ of its normal definition vector.
+ At other times, this is -1. */
+
+static int header_file_prev_index;
+
+/* At the start of reading dbx symbols, allocate our tables. */
+
+static void
+init_header_files ()
+{
+ n_allocated_header_files = 10;
+ header_files = (struct header_file *) xxmalloc (10 * sizeof (struct header_file));
+ n_header_files = 0;
+
+ n_allocated_this_object_header_files = 10;
+ this_object_header_files = (int *) xxmalloc (10 * sizeof (int));
+}
+
+/* At the end of reading dbx symbols, free our tables. */
+
+static void
+free_header_files ()
+{
+ register int i;
+ for (i = 0; i < n_header_files; i++)
+ free (header_files[i].name);
+ if (header_files) free (header_files);
+ if (this_object_header_files)
+ free (this_object_header_files);
+}
+
+/* Called at the start of each object file's symbols.
+ Clear out the mapping of header file numbers to header files. */
+
+static void
+new_object_header_files ()
+{
+ /* Leave FILENUM of 0 free for builtin types and this file's types. */
+ n_this_object_header_files = 1;
+ header_file_prev_index = -1;
+}
+
+/* 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 (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 (!strcmp (p[i].name, name) && instance == p[i].instance)
+ {
+ add_this_object_header_file (i);
+ return;
+ }
+ error ("Invalid symbol data: \"repeated\" header file that hasn't been seen before, at symtab pos %d.",
+ symnum);
+}
+
+/* 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;
+ register struct header_file *p = header_files;
+ header_file_prev_index = -1;
+
+#if 0
+ /* This code was used before I knew about the instance codes.
+ My first hypothesis is that it is not necessary now
+ that instance codes are handled. */
+
+ /* Has this header file a previous definition?
+ If so, make a new entry anyway so that this use in this source file
+ gets a separate entry. Later source files get the old entry.
+ Record here the index of the old entry, so that any type indices
+ not previously defined can get defined in the old entry as
+ well as in the new one. */
+
+ for (i = 0; i < n_header_files; i++)
+ if (!strcmp (p[i].name, name))
+ {
+ header_file_prev_index = i;
+ }
+
+#endif
+
+ /* 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 (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 **) xxmalloc (10 * sizeof (struct type *));
+ bzero (header_files[i].vector, 10 * sizeof (struct type *));
+
+ add_this_object_header_file (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. */
+
+static struct type **
+dbx_lookup_type (typenums)
+ int typenums[2];
+{
+ register int filenum = typenums[0], index = typenums[1];
+
+ if (filenum < 0 || filenum >= n_this_object_header_files)
+ error ("Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.",
+ filenum, index, symnum);
+
+ if (filenum == 0)
+ {
+ /* Type is defined outside of header files.
+ Find it in this object file's type vector. */
+ if (index >= type_vector_length)
+ {
+ type_vector_length *= 2;
+ type_vector = (struct typevector *)
+ xrealloc (type_vector,
+ (sizeof (struct typevector)
+ + type_vector_length * sizeof (struct type *)));
+ bzero (&type_vector->type[type_vector_length / 2],
+ type_vector_length * sizeof (struct type *) / 2);
+ }
+ return &type_vector->type[index];
+ }
+ else
+ {
+ register int real_filenum = this_object_header_files[filenum];
+ register struct header_file *f;
+
+ if (real_filenum >= n_header_files)
+ abort ();
+
+ f = &header_files[real_filenum];
+
+ if (index >= f->length)
+ {
+ f->length *= 2;
+ f->vector = (struct type **)
+ xrealloc (f->vector, f->length * sizeof (struct type *));
+ bzero (&f->vector[f->length / 2],
+ f->length * sizeof (struct type *) / 2);
+ }
+ return &f->vector[index];
+ }
+}
+
+/* Create a type object. Occaisionally used when you need a type
+ which isn't going to be given a type number. */
+
+static struct type *
+dbx_create_type ()
+{
+ register struct type *type =
+ (struct type *) obstack_alloc (symbol_obstack, sizeof (struct type));
+
+ bzero (type, sizeof (struct type));
+ TYPE_VPTR_FIELDNO (type) = -1;
+ return type;
+}
+
+/* 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)
+ int typenums[2];
+{
+ register struct type **type_addr;
+ register struct type *type;
+
+ if (typenums[1] != -1)
+ {
+ type_addr = dbx_lookup_type (typenums);
+ type = *type_addr;
+ }
+ else
+ {
+ type_addr = 0;
+ type = 0;
+ }
+
+ /* 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 == 0)
+ {
+ type = dbx_create_type ();
+ if (type_addr)
+ *type_addr = type;
+ }
+
+ return type;
+}
+
+#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 *));
+ bzero (&f->vector[f->length / 2],
+ f->length * sizeof (struct type *) / 2);
+ }
+ return &f->vector[index];
+}
+#endif
+
+/* maintain the lists of symbols and blocks */
+
+/* Add a symbol to one of the lists of symbols. */
+static void
+add_symbol_to_list (symbol, listhead)
+ struct symbol *symbol;
+ struct pending **listhead;
+{
+ /* 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 == 0 || (*listhead)->nsyms == PENDINGSIZE)
+ {
+ register struct pending *link;
+ if (free_pendings)
+ {
+ link = free_pendings;
+ free_pendings = link->next;
+ }
+ else
+ link = (struct pending *) xxmalloc (sizeof (struct pending));
+
+ link->next = *listhead;
+ *listhead = link;
+ link->nsyms = 0;
+ }
+
+ (*listhead)->symbol[(*listhead)->nsyms++] = symbol;
+}
+
+/* At end of reading syms, or in case of quit,
+ really free as many `struct pending's as we can easily find. */
+
+static void
+really_free_pendings ()
+{
+ struct pending *next, *next1;
+ struct pending_block *bnext, *bnext1;
+
+ for (next = free_pendings; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+ free_pendings = 0;
+
+ for (bnext = pending_blocks; bnext; bnext = bnext1)
+ {
+ bnext1 = bnext->next;
+ free (bnext);
+ }
+ pending_blocks = 0;
+
+ for (next = file_symbols; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+ for (next = global_symbols; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+}
+
+/* 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. */
+
+static void
+finish_block (symbol, listhead, old_blocks, start, end)
+ struct symbol *symbol;
+ struct pending **listhead;
+ struct pending_block *old_blocks;
+ CORE_ADDR start, end;
+{
+ register struct pending *next, *next1;
+ register struct block *block;
+ register struct pending_block *pblock;
+ struct pending_block *opblock;
+ register int i;
+
+ /* Count the length of the list of symbols. */
+
+ for (next = *listhead, i = 0; next; i += next->nsyms, next = next->next);
+
+ block = (struct block *) obstack_alloc (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)
+ {
+ register int j;
+ for (j = next->nsyms - 1; j >= 0; j--)
+ BLOCK_SYM (block, --i) = next->symbol[j];
+ }
+
+ BLOCK_START (block) = start;
+ BLOCK_END (block) = end;
+ BLOCK_SUPERBLOCK (block) = 0; /* Filled in when containing block is made */
+ 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) = 0;
+
+ /* 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 = 0;
+
+ /* Install this block as the superblock
+ of all blocks made since the start of this scope
+ that don't have superblocks yet. */
+
+ opblock = 0;
+ for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next)
+ {
+ if (BLOCK_SUPERBLOCK (pblock->block) == 0)
+ 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 (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 ()
+{
+ register struct pending_block *next, *next1;
+ 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 (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 = 0;
+
+ return blockvector;
+}
+
+/* Manage the vector of line numbers. */
+
+static void
+record_line (line, pc)
+ 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 is big enough. */
+
+ if (line_vector_index + 1 >= line_vector_length)
+ {
+ line_vector_length *= 2;
+ line_vector = (struct linetable *)
+ xrealloc (line_vector,
+ (sizeof (struct linetable)
+ + line_vector_length * sizeof (struct linetable_entry)));
+ current_subfile->line_vector = line_vector;
+ }
+
+ 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 dbx symbol of type N_SO is seen;
+ it indicates the start of data for one original source file. */
+
+static void
+start_symtab (name, start_addr)
+ char *name;
+ CORE_ADDR start_addr;
+{
+ register struct symtab *s;
+
+ last_source_file = name;
+ last_source_start_addr = start_addr;
+ file_symbols = 0;
+ global_symbols = 0;
+ within_function = 0;
+
+ /* Context stack is initially empty, with room for 10 levels. */
+ context_stack
+ = (struct context_stack *) xxmalloc (10 * sizeof (struct context_stack));
+ context_stack_size = 10;
+ context_stack_depth = 0;
+
+ new_object_header_files ();
+
+ for (s = symseg_chain; s; s = s->next)
+ if (s->ldsymoff == symnum * sizeof (struct nlist))
+ break;
+ current_symseg = s;
+ if (s != 0)
+ return;
+
+ type_vector_length = 160;
+ type_vector = (struct typevector *)
+ xxmalloc (sizeof (struct typevector)
+ + type_vector_length * sizeof (struct type *));
+ bzero (type_vector->type, type_vector_length * sizeof (struct type *));
+
+ /* Initialize the list of sub source files with one entry
+ for this file (the top-level source file). */
+
+ subfiles = 0;
+ current_subfile = 0;
+ start_subfile (name);
+
+#if 0 /* This is now set at the beginning of read_ofile_symtab */
+ /* Set default for compiler to pcc; assume that we aren't processing
+ a gcc compiled file until proved otherwise. */
+
+ processing_gcc_compilation = 0;
+#endif
+}
+
+/* Handle an N_SOL symbol, which indicates the start of
+ code that came from an included (or otherwise merged-in)
+ source file with a different name. */
+
+static void
+start_subfile (name)
+ char *name;
+{
+ register struct subfile *subfile;
+
+ /* Save the current subfile's line vector data. */
+
+ if (current_subfile)
+ {
+ current_subfile->line_vector_index = line_vector_index;
+ current_subfile->line_vector_length = line_vector_length;
+ current_subfile->prev_line_number = prev_line_number;
+ }
+
+ /* See if this subfile is already known as a subfile of the
+ current main source file. */
+
+ for (subfile = subfiles; subfile; subfile = subfile->next)
+ {
+ if (!strcmp (subfile->name, name))
+ {
+ line_vector = subfile->line_vector;
+ line_vector_index = subfile->line_vector_index;
+ line_vector_length = subfile->line_vector_length;
+ prev_line_number = subfile->prev_line_number;
+ current_subfile = subfile;
+ return;
+ }
+ }
+
+ /* This subfile is not known. Add an entry for it. */
+
+ line_vector_index = 0;
+ line_vector_length = 1000;
+ prev_line_number = -2; /* Force first line number to be explicit */
+ line_vector = (struct linetable *)
+ xxmalloc (sizeof (struct linetable)
+ + line_vector_length * sizeof (struct linetable_entry));
+
+ /* Make an entry for this subfile in the list of all subfiles
+ of the current main source file. */
+
+ subfile = (struct subfile *) xxmalloc (sizeof (struct subfile));
+ subfile->next = subfiles;
+ subfile->name = savestring (name, strlen (name));
+ subfile->line_vector = line_vector;
+ subfiles = subfile;
+ current_subfile = subfile;
+}
+
+/* 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. */
+
+static void
+end_symtab (end_addr)
+ CORE_ADDR end_addr;
+{
+ register struct symtab *symtab;
+ register struct blockvector *blockvector;
+ register struct subfile *subfile;
+ register struct linetable *lv;
+ struct subfile *nextsub;
+
+ if (current_symseg != 0)
+ {
+ last_source_file = 0;
+ current_symseg = 0;
+ return;
+ }
+
+ /* Finish the lexical context of the last function in the file;
+ pop the context stack. */
+
+ if (context_stack_depth > 0)
+ {
+ register struct context_stack *cstk;
+ 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);
+ }
+
+ /* 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). */
+ cleanup_undefined_types ();
+
+ /* Finish defining all the blocks of this symtab. */
+ finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr);
+ finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr);
+ blockvector = make_blockvector ();
+
+ current_subfile->line_vector_index = line_vector_index;
+
+ /* Now create the symtab objects proper, one for each subfile. */
+ /* (The main file is one of them.) */
+
+ for (subfile = subfiles; subfile; subfile = nextsub)
+ {
+ symtab = (struct symtab *) xxmalloc (sizeof (struct symtab));
+ symtab->free_ptr = 0;
+
+ /* Fill in its components. */
+ symtab->blockvector = blockvector;
+ type_vector->length = type_vector_length;
+ symtab->typevector = type_vector;
+ symtab->free_code = free_linetable;
+ if (subfile->next == 0)
+ symtab->free_ptr = (char *) type_vector;
+
+ symtab->filename = subfile->name;
+ lv = subfile->line_vector;
+ lv->nitems = subfile->line_vector_index;
+ symtab->linetable = (struct linetable *)
+ xrealloc (lv, (sizeof (struct linetable)
+ + lv->nitems * sizeof (struct linetable_entry)));
+ symtab->nlines = 0;
+ symtab->line_charpos = 0;
+
+ /* Link the new symtab into the list of such. */
+ symtab->next = symtab_list;
+ symtab_list = symtab;
+
+ nextsub = subfile->next;
+ free (subfile);
+ }
+
+ type_vector = 0;
+ type_vector_length = -1;
+ line_vector = 0;
+ line_vector_length = -1;
+ last_source_file = 0;
+}
+
+#ifdef N_BINCL
+
+/* 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. */
+
+struct subfile_stack
+{
+ struct subfile_stack *next;
+ char *name;
+ int prev_index;
+};
+
+struct subfile_stack *subfile_stack;
+
+static void
+push_subfile ()
+{
+ register struct subfile_stack *tem
+ = (struct subfile_stack *) xxmalloc (sizeof (struct subfile_stack));
+
+ tem->next = subfile_stack;
+ subfile_stack = tem;
+ if (current_subfile == 0 || current_subfile->name == 0)
+ abort ();
+ tem->name = current_subfile->name;
+ tem->prev_index = header_file_prev_index;
+}
+
+static char *
+pop_subfile ()
+{
+ register char *name;
+ register struct subfile_stack *link = subfile_stack;
+
+ if (link == 0)
+ abort ();
+
+ name = link->name;
+ subfile_stack = link->next;
+ header_file_prev_index = link->prev_index;
+ free (link);
+
+ return name;
+}
+#endif /* Have N_BINCL */
+
+/* Accumulate the misc functions in bunches of 127.
+ At the end, copy them all into one newly allocated structure. */
+
+#define MISC_BUNCH_SIZE 127
+
+struct misc_bunch
+{
+ struct misc_bunch *next;
+ struct misc_function contents[MISC_BUNCH_SIZE];
+};
+
+/* Bunch currently being filled up.
+ The next field points to chain of filled bunches. */
+
+static struct misc_bunch *misc_bunch;
+
+/* Number of slots filled in current bunch. */
+
+static int misc_bunch_index;
+
+/* Total number of misc functions recorded so far. */
+
+static int misc_count;
+
+static void
+init_misc_functions ()
+{
+ misc_count = 0;
+ misc_bunch = 0;
+ misc_bunch_index = MISC_BUNCH_SIZE;
+}
+
+static void
+record_misc_function (name, address, type)
+ char *name;
+ CORE_ADDR address;
+ int type;
+{
+ register struct misc_bunch *new;
+ register unsigned char mtype;
+
+ if (misc_bunch_index == MISC_BUNCH_SIZE)
+ {
+ new = (struct misc_bunch *) xxmalloc (sizeof (struct misc_bunch));
+ misc_bunch_index = 0;
+ new->next = misc_bunch;
+ misc_bunch = new;
+ }
+ misc_bunch->contents[misc_bunch_index].name = name;
+ misc_bunch->contents[misc_bunch_index].address = address;
+ switch (type &~ N_EXT)
+ {
+ case N_TEXT: mtype = mf_text; break;
+ case N_DATA: mtype = mf_data; break;
+ case N_BSS: mtype = mf_bss; break;
+ case N_ABS: mtype = mf_abs; break;
+#ifdef N_SETV
+ case N_SETV: mtype = mf_data; break;
+#endif
+ default: mtype = mf_unknown; break;
+ }
+ misc_bunch->contents[misc_bunch_index].type = mtype;
+ misc_bunch_index++;
+ misc_count++;
+}
+
+static int
+compare_misc_functions (fn1, fn2)
+ struct misc_function *fn1, *fn2;
+{
+ /* Return a signed result based on unsigned comparisons
+ so that we sort into unsigned numeric order. */
+ if (fn1->address < fn2->address)
+ return -1;
+ if (fn1->address > fn2->address)
+ return 1;
+ return 0;
+}
+
+static void
+discard_misc_bunches ()
+{
+ register struct misc_bunch *next;
+
+ while (misc_bunch)
+ {
+ next = misc_bunch->next;
+ free (misc_bunch);
+ misc_bunch = next;
+ }
+}
+
+/* INCLINK nonzero means bunches are from an incrementally-linked file.
+ Add them to the existing bunches.
+ Otherwise INCLINK is zero, and we start from scratch. */
+static void
+condense_misc_bunches (inclink)
+ int inclink;
+{
+ register int i, j;
+ register struct misc_bunch *bunch;
+#ifdef NAMES_HAVE_UNDERSCORE
+ int offset = 1;
+#else
+ int offset = 0;
+#endif
+
+ if (inclink)
+ {
+ misc_function_vector
+ = (struct misc_function *)
+ xrealloc (misc_function_vector, (misc_count + misc_function_count)
+ * sizeof (struct misc_function));
+ j = misc_function_count;
+ }
+ else
+ {
+ misc_function_vector
+ = (struct misc_function *)
+ xxmalloc (misc_count * sizeof (struct misc_function));
+ j = 0;
+ }
+
+ bunch = misc_bunch;
+ while (bunch)
+ {
+ for (i = 0; i < misc_bunch_index; i++)
+ {
+ misc_function_vector[j] = bunch->contents[i];
+ misc_function_vector[j].name
+ = obconcat (misc_function_vector[j].name
+ + (misc_function_vector[j].name[0] == '_' ? offset : 0),
+ "", "");
+ j++;
+ }
+ bunch = bunch->next;
+ misc_bunch_index = MISC_BUNCH_SIZE;
+ }
+
+ if (inclink)
+ misc_function_count += misc_count;
+ else
+ misc_function_count = j;
+
+ /* Sort the misc functions by address. */
+
+ qsort (misc_function_vector, misc_function_count,
+ sizeof (struct misc_function),
+ compare_misc_functions);
+
+ /* (re)build the hash table (positions changed during the sort) */
+
+ for (i = 0; i < MISC_FUNC_HASH_SIZE; ++i)
+ misc_function_hash_tab[i] = -1;
+ for (i = 0; i < misc_function_count; ++i)
+ {
+ j = hash_symbol(misc_function_vector[i].name) & (MISC_FUNC_HASH_SIZE - 1);
+ misc_function_vector[i].next = misc_function_hash_tab[j];
+ misc_function_hash_tab[j] = i;
+ }
+}
+
+/* Call sort_syms to sort alphabetically
+ the symbols of each block of each symtab. */
+
+static int
+compare_symbols (s1, s2)
+ struct symbol **s1, **s2;
+{
+ register int namediff;
+
+ /* Compare the initial characters. */
+ namediff = SYMBOL_NAME (*s1)[0] - SYMBOL_NAME (*s2)[0];
+ if (namediff != 0) return namediff;
+
+ /* If they match, compare the rest of the names. */
+ namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2));
+ if (namediff != 0) return namediff;
+
+ /* For symbols of the same name, registers should come first. */
+ return ((SYMBOL_CLASS (*s2) == LOC_REGISTER)
+ - (SYMBOL_CLASS (*s1) == LOC_REGISTER));
+}
+
+static void sort_symtab_syms ();
+
+static void
+sort_syms ()
+{
+ register struct symtab *s;
+
+ for (s = symtab_list; s; s = s->next)
+ sort_symtab_syms (s);
+}
+
+static void
+sort_symtab_syms (s)
+ register struct symtab *s;
+{
+ register struct blockvector *bv = BLOCKVECTOR (s);
+ int nbl = BLOCKVECTOR_NBLOCKS (bv);
+ int i;
+ register struct block *b;
+
+ /* Note that in the following sort, we always make sure that
+ register debug symbol declarations always come before regular
+ debug symbol declarations (as might happen when parameters are
+ then put into registers by the compiler). We do this by a
+ correct compare in compare_symbols, and by the reversal of the
+ symbols if we don't sort. This works as long as a register debug
+ symbol always comes after a parameter debug symbol. */
+
+ /* This is no longer necessary; lookup_block_symbol now always
+ prefers some other declaration over a parameter declaration. We
+ still sort the thing (that is necessary), but we don't reverse it
+ if we shouldn't sort it. */
+
+ for (i = 0; i < nbl; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ if (BLOCK_SHOULD_SORT (b))
+ qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
+ sizeof (struct symbol *), compare_symbols);
+ }
+}
+
+
+extern struct symtab *psymtab_to_symtab ();
+
+/* The entry point. */
+static CORE_ADDR entry_point;
+
+static char *symfile_string_table;
+static int symfile_string_table_size;
+
+/* This is the symbol-file command. Read the file, analyze its symbols,
+ and add a struct symtab to symtab_list. */
+
+void
+symbol_file_command (name, from_tty)
+ char *name;
+ int from_tty;
+{
+ register int desc;
+ DECLARE_FILE_HEADERS;
+ struct nlist *nlist;
+
+ /* The string table. */
+ char *stringtab;
+
+ /* The size of the string table (buffer is a bizarre name...). */
+ long buffer;
+
+ register int val;
+ extern void close ();
+ struct cleanup *old_chain;
+ struct symtab *symseg;
+ struct stat statbuf;
+
+ dont_repeat ();
+
+ if (name == 0)
+ {
+ if ((symtab_list || partial_symtab_list)
+ && from_tty
+ && !query ("Discard symbol table? ", 0))
+ error ("Not confirmed.");
+ if (symfile)
+ free (symfile);
+ symfile = 0;
+ free_all_symtabs ();
+ free_all_psymtabs ();
+ return;
+ }
+
+ name = tilde_expand (name);
+ make_cleanup (free, name);
+
+ if ((symtab_list || partial_symtab_list)
+ && !query ("Load new symbol table from \"%s\"? ", name))
+ error ("Not confirmed.");
+
+ {
+ char *absolute_name;
+ desc = openp (getenv ("PATH"), 1, name, O_RDONLY, 0, &absolute_name);
+ if (desc < 0)
+ perror_with_name (name);
+ else
+ name = absolute_name;
+ }
+
+ old_chain = make_cleanup (close, desc);
+ make_cleanup (free_current_contents, &name);
+
+ READ_FILE_HEADERS (desc, name);
+
+ entry_point = ENTRY_POINT;
+
+ if (NUMBER_OF_SYMBOLS == 0)
+ {
+ if (symfile)
+ free (symfile);
+ symfile = 0;
+ free_all_symtabs ();
+ free_all_psymtabs ();
+ printf ("%s has no symbol-table; symbols discarded.\n", name);
+ fflush (stdout);
+ do_cleanups (old_chain);
+ return;
+ }
+
+ printf ("Reading symbol data from %s...", name);
+ fflush (stdout);
+
+ /* Now read the string table, all at once. */
+ val = lseek (desc, STRING_TABLE_OFFSET, 0);
+ if (val < 0)
+ perror_with_name (name);
+ if (stat (name, &statbuf) == -1)
+ perror_with_name (name);
+ READ_STRING_TABLE_SIZE (buffer);
+ if (buffer >= 0 && buffer < statbuf.st_size)
+ {
+ /* This should speed things up without consuming much
+ extra memory (because probably little of the space is going
+ to be reused anyway, whether in data or stack space).
+
+ A quick test (running GDB on itself and setting 9 breakpoints
+ in different files) showed that memory usage was almost
+ identical for the two cases. */
+#if 0
+#ifdef BROKEN_LARGE_ALLOCA
+ stringtab = (char *) xmalloc (buffer);
+ make_cleanup (free, stringtab);
+#else
+ stringtab = (char *) alloca (buffer);
+#endif
+#endif
+ stringtab = (char *) xmalloc (buffer);
+ symfile_string_table = stringtab;
+ symfile_string_table_size = buffer;
+ }
+ else
+ stringtab = NULL;
+ if (stringtab == NULL)
+ error ("ridiculous string table size: %d bytes", buffer);
+
+ /* Usually READ_STRING_TABLE_SIZE will have shifted the file pointer.
+ Occaisionally, it won't. */
+ val = lseek (desc, STRING_TABLE_OFFSET, L_SET);
+ if (val < 0)
+ perror_with_name (name);
+ val = myread (desc, stringtab, buffer);
+ if (val < 0)
+ perror_with_name (name);
+
+ /* Throw away the old symbol table. */
+
+ if (symfile)
+ free (symfile);
+ symfile = 0;
+ free_all_symtabs ();
+ free_all_psymtabs ();
+
+ /* Empty the hash table of global syms looking for values. */
+ bzero (global_sym_chain, sizeof global_sym_chain);
+
+ /* Symsegs are no longer supported by GDB. Setting symseg_chain to
+ 0 is easier than finding all the symseg code and eliminating it. */
+ symseg_chain = 0;
+
+ /* Position to read the symbol table. Do not read it all at once. */
+ val = lseek (desc, SYMBOL_TABLE_OFFSET, 0);
+ if (val < 0)
+ perror_with_name (name);
+
+ /* Don't put these on the cleanup chain; they need to stick around
+ until the next call to symbol_file_command. *Then* we'll free
+ them. */
+ free_header_files ();
+ init_header_files ();
+
+ init_misc_functions ();
+ make_cleanup (discard_misc_bunches, 0);
+
+ free_pendings = 0;
+ pending_blocks = 0;
+ file_symbols = 0;
+ global_symbols = 0;
+ make_cleanup (really_free_pendings, 0);
+
+ /* Now that the symbol table data of the executable file are all in core,
+ process them and define symbols accordingly. Closes desc. */
+
+ read_dbx_symtab (desc, stringtab, buffer, NUMBER_OF_SYMBOLS, 0,
+ ADDR_OF_TEXT_SEGMENT, SIZE_OF_TEXT_SEGMENT);
+
+ /* Go over the misc functions and install them in vector. */
+
+ condense_misc_bunches (0);
+
+ /* Don't allow char * to have a typename (else would get caddr_t.) */
+
+ TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
+
+ /* Make a default for file to list. */
+
+ symfile = savestring (name, strlen (name));
+
+ /* Call to select_source_symtab used to be here; it was using too
+ much time. I'll make sure that list_sources can handle the lack
+ of current_source_symtab */
+
+ do_cleanups (old_chain); /* Descriptor closed here */
+
+ /* Free the symtabs made by read_symsegs, but not their contents,
+ which have been copied into symtabs on symtab_list. */
+ while (symseg_chain)
+ {
+ register struct symtab *s = symseg_chain->next;
+ free (symseg_chain);
+ symseg_chain = s;
+ }
+
+ if (!partial_symtab_list)
+ printf ("\n(no debugging symbols found)...");
+
+ printf ("done.\n");
+ fflush (stdout);
+}
+
+/* Return name of file symbols were loaded from, or 0 if none.. */
+
+char *
+get_sym_file ()
+{
+ return symfile;
+}
+
+/* Buffer for reading the symbol table entries. */
+static struct nlist symbuf[4096];
+static int symbuf_idx;
+static int symbuf_end;
+
+/* I/O descriptor for reading the symbol table. */
+static int symtab_input_desc;
+
+/* The address of the string table
+ of the object file we are reading (as copied into core). */
+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 int
+fill_symbuf ()
+{
+ int nbytes = myread (symtab_input_desc, symbuf, sizeof (symbuf));
+ if (nbytes <= 0)
+ error ("error or end of file reading symbol table");
+ symbuf_end = nbytes / sizeof (struct nlist);
+ symbuf_idx = 0;
+ return 1;
+}
+
+/* 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 *
+next_symbol_text ()
+{
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf ();
+ symnum++;
+ return symbuf[symbuf_idx++].n_un.n_strx + stringtab_global;
+}
+
+/*
+ * Initializes storage for all of the partial symbols that will be
+ * created by read_dbx_symtab and subsidiaries.
+ */
+void
+init_psymbol_list (total_symbols)
+ int total_symbols;
+{
+ /* Current best guess is that there are approximately a twentieth
+ of the total symbols (in a debugging file) are global or static
+ oriented symbols */
+ global_psymbols.size = total_symbols / 10;
+ static_psymbols.size = total_symbols / 10;
+ global_psymbols.next = global_psymbols.list = (struct partial_symbol *)
+ xmalloc (global_psymbols.size * sizeof (struct partial_symbol));
+ static_psymbols.next = static_psymbols.list = (struct partial_symbol *)
+ xmalloc (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)
+ int number;
+{
+ bincls_allocated = number;
+ next_bincl = bincl_list = (struct header_file_location *)
+ xmalloc (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 *)
+ xrealloc (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.
+ */
+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
+ && !strcmp (name, bincl->name))
+ return bincl->pst;
+
+ return (struct partial_symtab *) 0;
+}
+
+/*
+ * Free the storage allocated for the bincl list.
+ */
+static void
+free_bincl_list ()
+{
+ free (bincl_list);
+ bincls_allocated = 0;
+}
+
+static struct partial_symtab *start_psymtab ();
+static void add_psymtab_dependency ();
+static void end_psymtab();
+
+static int
+compare_psymbols (s1, s2)
+ register struct partial_symbol *s1, *s2;
+{
+ register char
+ *st1 = SYMBOL_NAME (s1),
+ *st2 = SYMBOL_NAME (s2);
+ register int i;
+
+ if (st1[0] - st2[0])
+ return (st1[0] - st2[0]);
+ if (st1[1] - st2[1])
+ return (st1[1] - st2[1]);
+ if (i = strcmp(st1, st2))
+ return (i);
+ /* Next comparison implements policy that used to be in lookup_symbol:
+ * it would search psymtabs in psymtab_list order (reverse order of
+ * declaration) & take first occurance of symbol it found. So, we
+ * collate duplicate names in reverse psymtab order. */
+ return (s2->pst - s1->pst);
+}
+
+/* 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. NLISTLEN is the number
+ of symbols in the symbol table. All symbol names are given as
+ offsets relative to STRINGTAB. STRINGTAB_SIZE is the size of
+ STRINGTAB.
+
+ I have no idea whether or not this routine should be setup to deal
+ with inclinks. It seems reasonable to me that they be dealt with
+ standardly, so I am not going to make a strong effort to deal with
+ them here.
+ */
+
+static void
+read_dbx_symtab (desc, stringtab, stringtab_size, nlistlen, inclink,
+ text_addr, text_size)
+ int desc;
+ register char *stringtab;
+ register long stringtab_size;
+ register int nlistlen;
+ int inclink;
+ unsigned text_addr;
+ int text_size;
+{
+ register struct nlist *bufp;
+ register char *namestring;
+ register struct partial_symbol *psym;
+ register struct psymbol_allocation_list *psymbol_struct;
+
+ int nsl;
+ int past_first_source_file = 0;
+ CORE_ADDR last_o_file_start = 0;
+ char *last_o_file_name = "*bogus*";
+ struct cleanup *old_chain;
+ char *p;
+ enum namespace ns;
+ enum address_class class;
+
+#ifdef PROFILE_TYPES
+ int i;
+ int profile_types [256];
+ int strcmp_called = 0;
+ int autovars = 0;
+ int global_funs = 0;
+#endif
+
+ /* 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;
+
+#ifdef PROFILE_TYPES
+ for (i = 0; i < 256; i++)
+ profile_types[i] = 0;
+#endif
+
+ stringtab_global = stringtab;
+
+ 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 *));
+
+ old_chain = make_cleanup (free_all_psymtabs, 0);
+
+ /* Init bincl list */
+ init_bincl_list (20);
+ make_cleanup (free_bincl_list, 0);
+
+ /* Setup global partial symbol list */
+ init_psymbol_list (nlistlen);
+
+ last_source_file = 0;
+
+#ifdef END_OF_TEXT_DEFAULT
+ end_of_text_addr = END_OF_TEXT_DEFAULT;
+#else
+ end_of_text_addr = text_addr + text_size;
+#endif
+
+ symtab_input_desc = desc; /* This is needed for fill_symbuf below */
+ symbuf_end = symbuf_idx = 0;
+
+ for (symnum = 0; symnum < nlistlen; 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 ();
+ bufp = &symbuf[symbuf_idx++];
+
+#ifdef PROFILE_TYPES
+ profile_types[bufp->n_type]++;
+#endif
+
+ /*
+ * Special case to speed up readin.
+ */
+ if (bufp->n_type == N_SLINE) continue;
+
+ /* Ok. There is a lot of code duplicated in the rest of this
+ switch statiement (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 index.
+ *) 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. */
+#define SET_NAMESTRING()\
+ if (bufp->n_un.n_strx < 0 || bufp->n_un.n_strx >= stringtab_size) \
+ error ("Invalid symbol data: bad string table offset: %d", \
+ bufp->n_un.n_strx); \
+ namestring = bufp->n_un.n_strx + stringtab
+
+#define ADD_PSYMBOL_TO_LIST(NAME, NAMELENGTH, NAMESPACE, CLASS, LIST, VALUE)\
+ do { \
+ if ((LIST).next >= \
+ (LIST).list + (LIST).size) \
+ { \
+ (LIST).list = (struct partial_symbol *) \
+ xrealloc ((LIST).list, \
+ ((LIST).size * 2 \
+ * sizeof (struct partial_symbol))); \
+ /* Next assumes we only went one over. Should be good if \
+ program works correctly */ \
+ (LIST).next = \
+ (LIST).list + (LIST).size; \
+ (LIST).size *= 2; \
+ } \
+ psym = (LIST).next++; \
+ \
+ SYMBOL_NAME (psym) = (char *) obstack_alloc (psymbol_obstack, \
+ (NAMELENGTH) + 1); \
+ strncpy (SYMBOL_NAME (psym), (NAME), (NAMELENGTH)); \
+ SYMBOL_NAME (psym)[(NAMELENGTH)] = '\0'; \
+ SYMBOL_NAMESPACE (psym) = (NAMESPACE); \
+ SYMBOL_CLASS (psym) = (CLASS); \
+ SYMBOL_VALUE (psym) = (VALUE); \
+ } while (0);
+
+
+ switch (bufp->n_type)
+ {
+ /*
+ * Standard, non-debugger, symbols
+ */
+
+ case N_TEXT | N_EXT:
+ /* Catch etext */
+
+ SET_NAMESTRING();
+
+ if (namestring[6] == '\0' && namestring[5] == 't'
+ && namestring[4] == 'x' && namestring[3] == 'e'
+ && namestring[2] == 't' && namestring[1] == 'e'
+ && namestring[0] == '_')
+ end_of_text_addr = bufp->n_value;
+
+ /* Figure out beginning and end of global linker symbol
+ section and put non-debugger specified symbols on
+ tmp_symchain */
+
+ last_global_sym = symnum;
+ if (!first_global_sym) first_global_sym = symnum;
+
+ record_misc_function (namestring, bufp->n_value,
+ bufp->n_type); /* Always */
+
+ continue;
+
+#ifdef N_NBTEXT
+ case N_NBTEXT | N_EXT:
+#endif
+#ifdef N_NBDATA
+ case N_NBDATA | N_EXT:
+#endif
+#ifdef N_NBBSS
+ case N_NBBSS | N_EXT:
+#endif
+#ifdef N_SETV
+ case N_SETV | N_EXT:
+#endif
+ case N_ABS | N_EXT:
+ case N_DATA | N_EXT:
+ case N_BSS | N_EXT:
+ /* Figure out beginning and end of global linker symbol
+ section and put non-debugger specified symbols on
+ tmp_symchain */
+
+ SET_NAMESTRING();
+
+ last_global_sym = symnum;
+ if (!first_global_sym) first_global_sym = symnum;
+
+ /* Not really a function here, but... */
+ record_misc_function (namestring, bufp->n_value,
+ bufp->n_type); /* Always */
+
+ continue;
+
+#ifdef N_NBTEXT
+ case N_NBTEXT:
+#endif
+
+ /* 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. */
+#if ! (N_FN & N_EXT)
+ case N_FN:
+#endif
+ case N_FN | N_EXT:
+ case N_TEXT:
+ SET_NAMESTRING();
+ if ((namestring[0] == '-' && namestring[1] == 'l')
+ || (namestring [(nsl = strlen (namestring)) - 1] == 'o'
+ && namestring [nsl - 2] == '.'))
+ {
+ if (entry_point < bufp->n_value
+ && entry_point >= last_o_file_start)
+ {
+ startup_file_start = last_o_file_start;
+ startup_file_end = bufp->n_value;
+ }
+ if (past_first_source_file && pst)
+ {
+ end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum * sizeof (struct nlist), bufp->n_value,
+ dependency_list, dependencies_used,
+ global_psymbols.next, static_psymbols.next);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ else
+ past_first_source_file = 1;
+ last_o_file_start = bufp->n_value;
+ last_o_file_name = namestring;
+ nsl = strlen(namestring);
+ if (namestring[nsl-2] == '.' && namestring[nsl-1] == 'o')
+ namestring[nsl-2] = 0;
+ }
+ else if (strcmp(namestring, "gcc_compiled."))
+ {
+ if (*namestring == '_')
+ ++namestring;
+ namestring = obconcat(last_o_file_name, ":", namestring);
+ last_global_sym = symnum;
+ if (!first_global_sym)
+ first_global_sym = symnum;
+ record_misc_function(namestring, bufp->n_value, bufp->n_type);
+ }
+ continue;
+
+ case N_ABS:
+ case N_DATA:
+ case N_BSS:
+ SET_NAMESTRING();
+ if (*namestring == '_')
+ ++namestring;
+ namestring = obconcat(last_o_file_name, ":", namestring);
+ last_global_sym = symnum;
+ if (!first_global_sym)
+ first_global_sym = symnum;
+ record_misc_function(namestring, bufp->n_value, bufp->n_type);
+ continue;
+
+ case N_UNDF:
+ case N_UNDF | N_EXT:
+#ifdef N_NBDATA
+ case N_NBDATA:
+#endif
+#ifdef N_NBBSS
+ case N_NBBSS:
+#endif
+
+ /* Keep going . . .*/
+
+ /*
+ * Special symbol types for GNU
+ */
+#ifdef N_INDR
+ case N_INDR:
+ case N_INDR | N_EXT:
+#endif
+#ifdef N_SETA
+ 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:
+#endif
+ continue;
+
+ /*
+ * Debugger symbols
+ */
+
+ case N_SO:
+ /* End the current partial symtab and start a new one */
+
+ SET_NAMESTRING();
+
+ if (pst && past_first_source_file)
+ {
+ end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum * sizeof (struct nlist), bufp->n_value,
+ dependency_list, dependencies_used,
+ global_psymbols.next, static_psymbols.next);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ else
+ past_first_source_file = 1;
+
+ pst = start_psymtab (namestring, bufp->n_value,
+ symnum * sizeof (struct nlist),
+ global_psymbols.next, static_psymbols.next);
+
+ continue;
+
+#ifdef N_BINCL
+ case N_BINCL:
+ /* 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 return */
+
+ SET_NAMESTRING();
+
+ add_bincl_to_list (pst, namestring, bufp->n_value);
+
+ /* Mark down an include file in the current psymtab */
+
+ 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 *));
+ bcopy (orig, psymtab_include_list,
+ includes_used * sizeof (char *));
+ }
+
+ continue;
+#endif
+
+ case N_SOL:
+ /* Mark down an include file in the current psymtab */
+
+ SET_NAMESTRING();
+
+ /* 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.
+
+ This seems to be a lot of time to be spending on N_SOL, but
+ things like "break expread.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). */
+ {
+ register int i;
+ for (i = 0; i < includes_used; i++)
+ if (!strcmp (namestring, psymtab_include_list[i]))
+ {
+ i = -1;
+ break;
+ }
+ if (i == -1)
+ continue;
+ }
+
+ 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 *));
+ bcopy (orig, psymtab_include_list,
+ includes_used * sizeof (char *));
+ }
+ continue;
+
+ case N_LSYM: /* Typedef or automatic variable. */
+ SET_NAMESTRING();
+
+ p = (char *) index (namestring, ':');
+
+ /* Skip if there is no :. */
+ if (!p) continue;
+
+ switch (p[1])
+ {
+ case 'T':
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ STRUCT_NAMESPACE, LOC_TYPEDEF,
+ static_psymbols, bufp->n_value);
+ goto check_enum;
+ case 't':
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ static_psymbols, bufp->n_value);
+ 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 separate
+ constant symbols ('c' N_LSYMS) for enum constants in
+ enums without names. */
+
+ /* 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. Skip over it. */
+ while ((*p >= '0' && *p <= '9')
+ || *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 = 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,
+ static_psymbols, 0);
+ /* 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,
+ static_psymbols, bufp->n_value);
+ continue;
+ default:
+#ifdef PROFILE_TYPES
+ if (isalpha(p[1]))
+ printf ("Funny...LSYM with a letter that isn't a type\n");
+ autovars++;
+#endif
+ /* Skip if the thing following the : is
+ not a letter (which indicates declaration of a local
+ variable, which we aren't interested in). */
+ continue;
+ }
+
+ case N_FUN:
+#if 0
+ /* This special-casing of N_FUN is just wrong; N_FUN
+ does not mean "function"; it means "text segment".
+ So N_FUN can go with 'V', etc. as well as 'f' or 'F'. */
+
+ SET_NAMESTRING();
+
+ p = (char *) index (namestring, ':');
+
+ if (!p || p[1] == 'F') continue;
+
+#ifdef PROFILE_TYPES
+ if (p[1] != 'f')
+ printf ("Funny...FUN with a letter that isn't 'F' or 'f'.\n");
+ global_funs++;
+#endif
+
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_BLOCK,
+ static_psymbols, bufp->n_value);
+
+ continue;
+#endif /* 0 */
+ case N_GSYM: /* Global (extern) variable; can be
+ data or bss (sigh). */
+ case N_STSYM: /* Data seg var -- static */
+ case N_LCSYM: /* BSS " */
+
+ /* 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. */
+#ifdef N_M2C
+ case N_M2C: /* I suspect that I can ignore this here. */
+ case N_SCOPE: /* Same. */
+#endif
+
+ SET_NAMESTRING();
+
+ p = (char *) index (namestring, ':');
+ if (!p)
+ continue; /* Not a debugging symbol. */
+
+ process_symbol_for_psymtab:
+
+ /* 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 'c':
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_CONST,
+ static_psymbols, bufp->n_value);
+ continue;
+ case 'S':
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_STATIC,
+ static_psymbols, bufp->n_value);
+ continue;
+ case 'G':
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_EXTERNAL,
+ global_psymbols, bufp->n_value);
+ continue;
+
+ case 't':
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_TYPEDEF,
+ global_psymbols, bufp->n_value);
+ continue;
+
+ case 'f':
+ ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+ VAR_NAMESPACE, LOC_BLOCK,
+ static_psymbols, bufp->n_value);
+ 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':
+ /* Global functions are ignored here. I'm not
+ sure what psymtab they go into (or just the misc
+ function vector). */
+ case 'F':
+ continue;
+
+ default:
+ fatal ("Internal error: Unexpected debugging symbol type '%c' at symnum %d.\n",
+ p[1], symnum);
+ }
+
+#ifdef N_BINCL
+ case N_EXCL:
+
+ 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, bufp->n_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 *));
+ bcopy (orig, dependency_list,
+ (dependencies_used
+ * sizeof (struct partial_symtab *)));
+#ifdef DEBUG_INFO
+ fprintf (stderr, "Had to reallocate dependency list.\n");
+ fprintf (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);
+ }
+ continue;
+
+ case N_EINCL:
+#endif
+#ifdef N_DSLINE
+ case N_DSLINE:
+#endif
+#ifdef N_BSLINE
+ case N_BSLINE:
+#endif
+ case N_SSYM: /* Claim: Structure or union element.
+ Hopefully, I can ignore this. */
+ case N_ENTRY: /* Alternate entry point; can ignore. */
+#ifdef N_MAIN
+ case N_MAIN: /* Can definitely ignore this. */
+#endif
+ 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_RBRAC:
+ /* These symbols aren't interesting; don't worry about them */
+
+ continue;
+
+ default:
+ /* If we haven't found it yet, we've got problems */
+
+ if (IGNORE_SYMBOL (bufp->n_type))
+ continue;
+
+ fatal ("Bad symbol type 0x%x encountered in gdb scan", bufp->n_type);
+ }
+ }
+
+ /* If there's stuff to be cleaned up, clean it up. */
+ if (entry_point < bufp->n_value
+ && entry_point >= last_o_file_start)
+ {
+ startup_file_start = last_o_file_start;
+ startup_file_end = bufp->n_value;
+ }
+
+ if (pst)
+ {
+ end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum * sizeof (struct nlist), end_of_text_addr,
+ dependency_list, dependencies_used,
+ global_psymbols.next, static_psymbols.next);
+ includes_used = 0;
+ dependencies_used = 0;
+ pst = (struct partial_symtab *) 0;
+ }
+
+ /* sort the global & static symtab list so we can binary search them */
+ qsort (global_psymbols.list, global_psymbols.next - global_psymbols.list,
+ sizeof (struct partial_symbol), compare_psymbols);
+ qsort (static_psymbols.list, static_psymbols.next - static_psymbols.list,
+ sizeof (struct partial_symbol), compare_psymbols);
+ free_bincl_list ();
+ discard_cleanups (old_chain);
+#ifdef PROFILE_TYPES
+ {
+ int i, j;
+#define __define_stab(SYM, NUMBER, NAME) {NUMBER, NAME},
+ static struct xyzzy {
+ unsigned char symnum;
+ char *name;
+ } tmp_list[] = {
+#include "stab.def"
+ {0x1, "eREF"},
+ {0x2, "ABS"},
+ {0x3, "eABS"},
+ {0x4, "TEXT"},
+ {0x5, "eTEXT"},
+ {0x6, "DATA"},
+ {0x7, "eDATA"},
+ {0x8, "BSS"},
+ {0x9, "eBSS"},
+ {0x12, "COMM"},
+ {0x13, "eCOMM"},
+ {0x1f, "FN"},
+ {0, "Unknown"},
+};
+ for (i = 0; i < 256; i++)
+ {
+ for (j = 0; j < (sizeof (tmp_list) / sizeof (struct xyzzy)) - 1; j++)
+ if (tmp_list[j].symnum == i)
+ break;
+ printf ("Symbol \"%s\" (0x%x) occured %d times.\n",
+ tmp_list[j].name, i, profile_types[i]);
+ }
+ printf ("Auto vars (under LSYM): %d\n", autovars);
+ printf ("Global funs (under FUN): %d\n", global_funs);
+ }
+#endif
+}
+
+/*
+ * Allocate and partially fill a partial symtab. It will be
+ * completely filled at the end of the symbol list.
+ */
+static struct partial_symtab *
+start_psymtab (filename, textlow, ldsymoff, global_syms, static_syms)
+ char *filename;
+ int textlow;
+ int ldsymoff;
+ struct partial_symbol *global_syms;
+ struct partial_symbol *static_syms;
+{
+ struct partial_symtab *result =
+ (struct partial_symtab *) obstack_alloc (psymbol_obstack,
+ sizeof (struct partial_symtab));
+
+ result->filename =
+ (char *) obstack_alloc (psymbol_obstack,
+ strlen (filename) + 1);
+ strcpy (result->filename, filename);
+
+ result->textlow = textlow;
+ result->ldsymoff = ldsymoff;
+
+ result->readin = 0;
+
+ result->globals_offset = global_syms - global_psymbols.list;
+ result->statics_offset = static_syms - static_psymbols.list;
+
+ result->n_global_syms = 0;
+ result->n_static_syms = 0;
+
+ return result;
+}
+
+
+/* Close off the current usage of a partial_symbol table entry. This
+ involves setting the correct number of includes (with a realloc),
+ setting the high text mark, setting the symbol length in the
+ executable, and setting the length of the global and static lists
+ of psymbols.
+
+ The global symbols and static symbols are then seperately sorted.
+
+ Then the partial symtab is put on the global list.
+ *** List variables and peculiarities of same. ***
+ */
+static void
+end_psymtab (pst, include_list, num_includes, capping_symbol_offset,
+ capping_text, dependency_list, number_dependencies,
+ capping_global, capping_static)
+ struct partial_symtab *pst;
+ char **include_list;
+ int num_includes;
+ int capping_symbol_offset;
+ int capping_text;
+ struct partial_symtab **dependency_list;
+ int number_dependencies;
+ struct partial_symbol *capping_global, *capping_static;
+{
+ int i;
+ register struct partial_symbol *ps;
+
+ pst->ldsymlen = capping_symbol_offset - pst->ldsymoff;
+ pst->texthigh = capping_text;
+
+ pst->n_global_syms =
+ capping_global - (global_psymbols.list + pst->globals_offset);
+ pst->n_static_syms =
+ capping_static - (static_psymbols.list + pst->statics_offset);
+
+ pst->dependencies = (struct partial_symtab **)
+ obstack_alloc (psymbol_obstack,
+ number_dependencies * sizeof (struct partial_symtab *));
+ bcopy (dependency_list, pst->dependencies,
+ number_dependencies * sizeof (struct partial_symtab *));
+ pst->number_of_dependencies = number_dependencies;
+
+ for (i = 0; i < num_includes; i++)
+ {
+ /* Eventually, put this on obstack */
+ struct partial_symtab *subpst =
+ (struct partial_symtab *)
+ obstack_alloc (psymbol_obstack,
+ sizeof (struct partial_symtab));
+
+ subpst->filename =
+ (char *) obstack_alloc (psymbol_obstack,
+ strlen (include_list[i]) + 1);
+ strcpy (subpst->filename, include_list[i]);
+
+ subpst->ldsymoff =
+ subpst->ldsymlen =
+ subpst->textlow =
+ subpst->texthigh = 0;
+ subpst->readin = 0;
+
+ subpst->dependencies = (struct partial_symtab **)
+ obstack_alloc (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->next = partial_symtab_list;
+ partial_symtab_list = subpst;
+ }
+
+ for (ps = global_psymbols.list + pst->globals_offset;
+ ps < capping_global; ++ps)
+ ps->pst = pst;
+ for (ps = static_psymbols.list + pst->statics_offset;
+ ps < capping_static; ++ps)
+ ps->pst = pst;
+
+ /* Put the psymtab on the psymtab list */
+ pst->next = partial_symtab_list;
+ partial_symtab_list = pst;
+}
+
+
+/* Helper routines for psymtab_to_symtab. */
+static void scan_file_globals ();
+static void read_ofile_symtab ();
+
+static void
+psymtab_to_symtab_1 (pst, desc, stringtab, stringtab_size, sym_offset)
+ struct partial_symtab *pst;
+ int desc;
+ char *stringtab;
+ int stringtab_size;
+ int sym_offset;
+{
+ struct cleanup *old_chain;
+ int i;
+
+ if (!pst)
+ return;
+
+ if (pst->readin)
+ {
+ fprintf (stderr, "Psymtab for %s already read in. Shouldn't happen.\n",
+ pst->filename);
+ return;
+ }
+
+ /* Read in all partial symbtabs 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)
+ {
+ printf_filtered (" and %s...", pst->dependencies[i]->filename);
+ fflush (stdout);
+ }
+ psymtab_to_symtab_1 (pst->dependencies[i], desc,
+ stringtab, stringtab_size, sym_offset);
+ }
+
+ if (pst->ldsymlen) /* Otherwise it's a dummy */
+ {
+ /* Init stuff necessary for reading in symbols */
+ free_pendings = 0;
+ pending_blocks = 0;
+ file_symbols = 0;
+ global_symbols = 0;
+ old_chain = make_cleanup (really_free_pendings, 0);
+
+ /* Read in this files symbols */
+ lseek (desc, sym_offset, L_SET);
+ read_ofile_symtab (desc, stringtab, stringtab_size,
+ pst->ldsymoff,
+ pst->ldsymlen, pst->textlow,
+ pst->texthigh - pst->textlow, 0);
+ sort_symtab_syms (symtab_list); /* At beginning since just added */
+
+ do_cleanups (old_chain);
+ }
+
+ pst->readin = 1;
+}
+
+/*
+ * Read in all of the symbols for a given psymtab for real. Return
+ * the value of the symtab you create. Do not free the storage
+ * allocated to the psymtab; it may have pointers to it.
+ */
+struct symtab *
+psymtab_to_symtab(pst)
+ struct partial_symtab *pst;
+{
+ int desc;
+ DECLARE_FILE_HEADERS;
+ char *stringtab;
+ struct partial_symtab **list_patch;
+ int stsize, val;
+ struct stat statbuf;
+ struct cleanup *old_chain;
+ extern void close ();
+ int i;
+ struct symtab *result;
+ char *name = symfile; /* Some of the macros require the */
+ /* variable "name" to be defined in */
+ /* the context in which they execute */
+ /* (Yech!) */
+
+ if (!pst)
+ return 0;
+
+ if (pst->readin)
+ {
+ fprintf (stderr, "Psymtab for %s already read in. Shouldn't happen.\n",
+ pst->filename);
+ return 0;
+ }
+
+ if (!name)
+ error("No symbol file currently specified; use command symbol-file");
+
+ if (pst->ldsymlen || 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);
+ fflush (stdout);
+ }
+
+ /* Open symbol file and read in string table */
+ if (stat (name, &statbuf) < 0)
+ perror_with_name (name);
+ desc = open(name, O_RDONLY, 0); /* symbol_file_command
+ guarrantees that the symbol file name
+ will be absolute, so there is no
+ need for openp */
+
+ old_chain = make_cleanup (close, desc);
+
+ if (desc < 0)
+ error("Symbol file not readable");
+
+ READ_FILE_HEADERS (desc, name);
+
+#if 0
+ /* Read in the string table */
+ lseek (desc, STRING_TABLE_OFFSET, L_SET);
+ READ_STRING_TABLE_SIZE (stsize);
+ if (stsize >= 0 && stsize < statbuf.st_size)
+ {
+#ifdef BROKEN_LARGE_ALLOCA
+ stringtab = (char *) xmalloc (stsize);
+ make_cleanup (free, stringtab);
+#else
+ stringtab = (char *) alloca (stsize);
+#endif
+ }
+ else
+ stringtab = NULL;
+ if (stringtab == NULL)
+ error ("ridiculous string table size: %d bytes", stsize);
+
+ /* Usually READ_STRING_TABLE_SIZE will have shifted the file pointer.
+ Occaisionally, it won't. */
+ val = lseek (desc, STRING_TABLE_OFFSET, L_SET);
+ if (val < 0)
+ perror_with_name (name);
+ val = myread (desc, stringtab, stsize);
+ if (val < 0)
+ perror_with_name (name);
+#endif /* 0 */
+ stringtab = symfile_string_table;
+ stsize = symfile_string_table_size;
+
+ psymtab_to_symtab_1 (pst, desc, stringtab, stsize,
+ SYMBOL_TABLE_OFFSET);
+
+ /* 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 ();
+
+ do_cleanups (old_chain);
+
+ /* Finish up the debug error message. */
+ if (info_verbose)
+ printf_filtered ("done.\n");
+ }
+
+ /* Search through list for correct name. */
+ for (result = symtab_list; result; result = result->next)
+ if (!strcmp (result->filename, pst->filename))
+ return result;
+
+ return 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 misc function list.
+ */
+static void
+scan_file_globals ()
+{
+ int hash;
+ int mf;
+
+ for (mf = 0; mf < misc_function_count; mf++)
+ {
+ char *namestring = misc_function_vector[mf].name;
+ struct symbol *sym, *prev;
+
+ QUIT;
+
+ prev = (struct symbol *) 0;
+
+ /* Get the hash index and check all the symbols
+ under that hash index. */
+
+ hash = hashname (namestring);
+
+ for (sym = global_sym_chain[hash]; sym;)
+ {
+ if (*namestring == SYMBOL_NAME (sym)[0]
+ && !strcmp(namestring + 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 (prev) = SYMBOL_VALUE (sym);
+ else
+ global_sym_chain[hash]
+ = (struct symbol *) SYMBOL_VALUE (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, misc_function_vector[mf].address);
+ else
+ SYMBOL_VALUE (sym) = misc_function_vector[mf].address;
+
+ if (prev)
+ sym = (struct symbol *) SYMBOL_VALUE (prev);
+ else
+ sym = global_sym_chain[hash];
+ }
+ else
+ {
+ prev = sym;
+ sym = (struct symbol *) SYMBOL_VALUE (sym);
+ }
+ }
+ }
+}
+
+/*
+ * Read in a defined section of a specific object file's symbols.
+ *
+ * DESC is the file descriptor for the file, positioned at the
+ * beginning of the symtab
+ * STRINGTAB is a pointer to the files string
+ * table, already read in
+ * SYM_OFFSET is the offset within the file of
+ * the beginning of the symbols we want to read, NUM_SUMBOLS is the
+ * number of symbols to read
+ * TEXT_OFFSET is the offset to be added to
+ * all values of symbols coming in and
+ * TEXT_SIZE is the size of the text segment read in.
+ * OFFSET is a flag which indicates that the value of all of the
+ * symbols should be offset by TEXT_OFFSET (for the purposes of
+ * incremental linking).
+ */
+
+static void
+read_ofile_symtab (desc, stringtab, stringtab_size, sym_offset,
+ sym_size, text_offset, text_size, offset)
+ int desc;
+ register char *stringtab;
+ int sym_offset;
+ int sym_size;
+ int text_offset;
+ int text_size;
+ int offset;
+{
+ register char *namestring;
+ register struct symbol *sym, *prev;
+ int hash;
+ struct cleanup *old_chain;
+ struct nlist *bufp;
+ unsigned char type;
+#ifdef N_BINCL
+ subfile_stack = 0;
+#endif
+
+ stringtab_global = stringtab;
+ last_source_file = 0;
+
+ symtab_input_desc = desc;
+ 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 (sym_offset >= sizeof (struct nlist))
+ {
+ lseek (desc, sym_offset - sizeof (struct nlist), L_INCR);
+ fill_symbuf ();
+ bufp = &symbuf[symbuf_idx++];
+
+ if (bufp->n_un.n_strx < 0 || bufp->n_un.n_strx >= stringtab_size)
+ error ("Invalid symbol data: bad string table offset: %d",
+ bufp->n_un.n_strx);
+ namestring = bufp->n_un.n_strx + stringtab;
+
+ processing_gcc_compilation =
+ (bufp->n_type == N_TEXT
+ && !strcmp (namestring, GCC_COMPILED_FLAG_SYMBOL));
+ }
+ 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. */
+ lseek(desc, sym_offset, L_INCR);
+ processing_gcc_compilation = 0;
+ }
+
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf();
+ bufp = &symbuf[symbuf_idx];
+ if ((unsigned char) bufp->n_type != N_SO)
+ fatal("First symbol in segment of executable not a source symbol");
+
+ for (symnum = 0;
+ symnum < sym_size / sizeof(struct nlist);
+ symnum++)
+ {
+ QUIT; /* Allow this to be interruptable */
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf();
+ bufp = &symbuf[symbuf_idx++];
+ type = bufp->n_type;
+
+ if (offset &&
+ (type == N_TEXT || type == N_DATA || type == N_BSS))
+ bufp->n_value += text_offset;
+
+ if (bufp->n_un.n_strx < 0 || bufp->n_un.n_strx >= stringtab_size)
+ error ("Invalid symbol data: bad string table offset: %d",
+ bufp->n_un.n_strx);
+ namestring = bufp->n_un.n_strx + stringtab;
+
+ if (type & N_STAB)
+ process_one_symbol(type, bufp->n_desc,
+ bufp->n_value, namestring);
+ /* We skip checking for a new .o or -l file; that should never
+ happen in this routine. */
+ else if (type == N_TEXT
+ && !strcmp (namestring, GCC_COMPILED_FLAG_SYMBOL))
+ /* 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. */
+ processing_gcc_compilation = 1;
+ else if (type & N_EXT || type == N_TEXT
+#ifdef N_NBTEXT
+ || type == N_NBTEXT
+#endif
+ )
+ /* 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. */
+ &stringtab_global; /* For debugger; am I right? */
+ }
+ end_symtab (text_offset + text_size);
+}
+
+static 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;
+}
+
+/* Put all appropriate global symbols in the symseg data
+ onto the hash chains so that their addresses will be stored
+ when seen later in loader global symbols. */
+
+static void
+hash_symsegs ()
+{
+ /* Look at each symbol in each block in each symseg symtab. */
+ struct symtab *s;
+ for (s = symseg_chain; s; s = s->next)
+ {
+ register int n;
+ for (n = BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (s)) - 1; n >= 0; n--)
+ {
+ register struct block *b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), n);
+ register int i;
+ for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--)
+ {
+ register struct symbol *sym = BLOCK_SYM (b, i);
+
+ /* Put the symbol on a chain if its value is an address
+ that is figured out by the loader. */
+
+ if (SYMBOL_CLASS (sym) == LOC_EXTERNAL)
+ {
+ register int hash = hashname (SYMBOL_NAME (sym));
+ SYMBOL_VALUE (sym) = (int) global_sym_chain[hash];
+ global_sym_chain[hash] = sym;
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ }
+ }
+ }
+ }
+}
+
+static void
+process_one_symbol (type, desc, value, name)
+ int type, desc;
+ CORE_ADDR value;
+ char *name;
+{
+ register struct context_stack *new;
+ char *colon_pos;
+
+ /* Something is wrong if we see real data before
+ seeing a source file name. */
+
+ if (last_source_file == 0 && type != N_SO)
+ {
+ /* Currently this ignores N_ENTRY on Gould machines, N_NSYM on machines
+ where that code is defined. */
+ if (IGNORE_SYMBOL (type))
+ return;
+
+ error ("Invalid symbol data: does not start by identifying a source file.");
+ }
+
+ switch (type)
+ {
+ case N_FUN:
+ case N_FNAME:
+ /* Either of these types of symbols indicates the start of
+ a new function. We must process its "name" normally for dbx,
+ but also record the start of a new lexical context, and possibly
+ also the end of the lexical context for the previous function. */
+ /* This is not always true. This type of symbol may indicate a
+ text segment variable. */
+
+ colon_pos = index (name, ':');
+ if (!colon_pos++
+ || (*colon_pos != 'f' && *colon_pos != 'F'))
+ {
+ define_symbol (value, name, desc);
+ break;
+ }
+
+ within_function = 1;
+ if (context_stack_depth > 0)
+ {
+ new = &context_stack[--context_stack_depth];
+ /* Make a block for the local symbols within. */
+ finish_block (new->name, &local_symbols, new->old_blocks,
+ new->start_addr, value);
+ }
+ /* Stack must be empty now. */
+ if (context_stack_depth != 0)
+ error ("Invalid symbol data: unmatched N_LBRAC before symtab pos %d.",
+ symnum);
+
+ new = &context_stack[context_stack_depth++];
+ new->old_blocks = pending_blocks;
+ new->start_addr = value;
+ new->name = define_symbol (value, name, desc);
+ local_symbols = 0;
+ break;
+
+ case N_LBRAC:
+ /* This "symbol" just indicates the start of an inner lexical
+ context within a function. */
+
+ if (context_stack_depth == context_stack_size)
+ {
+ context_stack_size *= 2;
+ context_stack = (struct context_stack *)
+ xrealloc (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 = value;
+ new->name = 0;
+ local_symbols = 0;
+ break;
+
+ case N_RBRAC:
+ /* This "symbol" just indicates the end of an inner lexical
+ context that was started with N_LBRAC. */
+ new = &context_stack[--context_stack_depth];
+ if (desc != new->depth)
+ error ("Invalid symbol data: N_LBRAC/N_RBRAC symbol mismatch, symtab pos %d.", symnum);
+
+ /* Some native 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. */
+#if !defined (VARIABLES_INSIDE_BLOCK)
+#define VARIABLES_INSIDE_BLOCK(desc) 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))
+ local_symbols = new->locals;
+
+ /* If 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. Defined the block for them.
+
+ If 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. However, if
+ it is so, we need to indicate that we just moved outside
+ of the function. */
+ if (local_symbols
+ && context_stack_depth > !VARIABLES_INSIDE_BLOCK(desc))
+ {
+ /* Muzzle a compiler bug that makes end < start. */
+ if (new->start_addr > value)
+ new->start_addr = value;
+ /* Make a block for the local symbols within. */
+ finish_block (0, &local_symbols, new->old_blocks,
+ new->start_addr + last_source_start_addr,
+ value + last_source_start_addr);
+ }
+ else
+ {
+ within_function = 0;
+ }
+ if (VARIABLES_INSIDE_BLOCK(desc))
+ /* Now pop locals of block just finished. */
+ local_symbols = new->locals;
+ break;
+
+ case N_FN | N_EXT:
+ /* This kind of symbol supposedly indicates the start
+ of an object file. In fact this type does not appear. */
+ 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. */
+#ifdef PCC_SOL_BROKEN
+ /* pcc bug, occasionally puts out SO for SOL. */
+ if (context_stack_depth > 0)
+ {
+ start_subfile (name);
+ break;
+ }
+#endif
+ if (last_source_file)
+ end_symtab (value);
+ start_symtab (name, value);
+ 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.) */
+ start_subfile (name);
+ break;
+
+#ifdef N_BINCL
+ case N_BINCL:
+ push_subfile ();
+ add_new_header_file (name, value);
+ start_subfile (name);
+ break;
+
+ case N_EINCL:
+ start_subfile (pop_subfile ());
+ break;
+
+ case N_EXCL:
+ add_old_header_file (name, value);
+ break;
+#endif /* have N_BINCL */
+
+ 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. */
+ record_line (desc, value);
+ break;
+
+ case N_BCOMM:
+ if (common_block)
+ error ("Invalid symbol data: common within common at symtab pos %d",
+ symnum);
+ common_block = local_symbols;
+ common_block_i = local_symbols ? local_symbols->nsyms : 0;
+ break;
+
+ case N_ECOMM:
+ /* Symbols declared since the BCOMM are to have the common block
+ start address added in when we know it. common_block points 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 pending *link = local_symbols;
+ struct symbol *sym =
+ (struct symbol *) xmalloc (sizeof (struct symbol));
+ bzero (sym, sizeof *sym);
+ SYMBOL_NAME (sym) = savestring (name, strlen (name));
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_NAMESPACE (sym) = (enum namespace)((long)
+ copy_pending (local_symbols, common_block_i, common_block));
+ i = hashname (SYMBOL_NAME (sym));
+ SYMBOL_VALUE (sym) = (int) global_sym_chain[i];
+ global_sym_chain[i] = sym;
+ common_block = 0;
+ break;
+ }
+
+ case N_ECOML:
+ case N_LENG:
+ break;
+
+ default:
+ if (name)
+ define_symbol (value, name, desc);
+ }
+}
+
+/* This function was added for C++ functionality. I presume that it
+ condenses the bunches formed by reading in an additional .o file
+ (incremental linking). */
+
+static void
+condense_addl_misc_bunches ()
+{
+ register int i, j;
+ register struct misc_bunch *bunch;
+#ifdef NAMES_HAVE_UNDERSCORE
+ int offset = 1;
+#else
+ int offset = 0;
+#endif
+
+ misc_function_vector
+ = (struct misc_function *) xrealloc (misc_function_vector,
+ (misc_count + misc_function_count) * sizeof (struct misc_function));
+
+ j = misc_function_count;
+ bunch = misc_bunch;
+ while (bunch)
+ {
+ for (i = 0; i < misc_bunch_index; i++)
+ {
+ misc_function_vector[j] = bunch->contents[i];
+ misc_function_vector[j].name
+ = concat (misc_function_vector[j].name
+ + (misc_function_vector[j].name[0] == '_' ? offset : 0),
+ "", "");
+ j++;
+ }
+ bunch = bunch->next;
+ misc_bunch_index = MISC_BUNCH_SIZE;
+ }
+
+ misc_function_count += misc_count;
+
+ /* Sort the misc functions by address. */
+
+ qsort (misc_function_vector, misc_function_count,
+ sizeof (struct misc_function), compare_misc_functions);
+}
+
+
+/* Read in another .o file and create a symtab entry for it.*/
+
+static void
+read_addl_syms (desc, stringtab, nlistlen, text_addr, text_size)
+ int desc;
+ register char *stringtab;
+ register int nlistlen;
+ unsigned text_addr;
+ int text_size;
+{
+ FILE *stream = fdopen (desc, "r");
+ register char *namestring;
+ register struct symbol *sym, *prev;
+ int hash;
+
+#ifdef N_BINCL
+ subfile_stack = 0;
+#endif
+
+ last_source_file = 0;
+ bzero (global_sym_chain, sizeof global_sym_chain);
+ symtab_input_desc = desc;
+ stringtab_global = stringtab;
+ fill_symbuf ();
+
+ for (symnum = 0; symnum < nlistlen; symnum++)
+ {
+ struct nlist *bufp;
+ unsigned char type;
+
+ QUIT; /* allow this to be interruptable */
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf ();
+ bufp = &symbuf[symbuf_idx++];
+ type = bufp->n_type & N_TYPE;
+ namestring = bufp->n_un.n_strx + stringtab;
+
+ if( (type == N_TEXT) || (type == N_DATA) || (type == N_BSS) )
+ {
+ /* Relocate this file's symbol table information
+ to the address it has been loaded into. */
+ bufp->n_value += text_addr;
+ }
+
+ type = bufp->n_type;
+
+ if (type & N_STAB)
+ process_one_symbol (type, bufp->n_desc,
+ bufp->n_value, namestring);
+ /* A static text symbol whose name ends in ".o"
+ can only mean the start of another object file.
+ So end the symtab of the source file we have been processing.
+ This is how we avoid counting the libraries as part
+ or the last source file.
+ Also this way we find end of first object file (crt0). */
+ else if ((type == N_TEXT
+#ifdef N_NBTEXT
+ || type == N_NBTEXT
+#endif
+ )
+ && (!strcmp (namestring + strlen (namestring) - 2, ".o"))
+ || ! strncmp (namestring, "-l", 2))
+ {
+ if (last_source_file)
+ end_symtab (bufp->n_value);
+ }
+ else if (type & N_EXT || type == N_TEXT
+#ifdef N_NBTEXT
+ || type == N_NBTEXT
+#endif
+ )
+ {
+ int used_up = 0;
+
+ /* Record the location of _etext. */
+ if (type == (N_TEXT | N_EXT)
+ && !strcmp (namestring, "_etext"))
+ end_of_text_addr = bufp->n_value;
+
+#if 0
+ /* 25 Sep 89: The following seems to be stolen from
+ read_ofile_symtab, and is wrong here (i.e. there was no
+ first pass for add-file symbols). */
+ /* This shouldn't be necessary, as we now do all of this work
+ in scan_global syms and all misc functions should have been
+ recorded on the first pass. */
+ /* Global symbol: see if we came across a dbx definition
+ 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. */
+ if (type & N_EXT)
+ {
+ prev = 0;
+#ifdef NAMES_HAVE_UNDERSCORE
+ hash = hashname (namestring + 1);
+#else /* not NAMES_HAVE_UNDERSCORE */
+ hash = hashname (namestring);
+#endif /* not NAMES_HAVE_UNDERSCORE */
+ for (sym = global_sym_chain[hash];
+ sym;)
+ {
+ if (
+#ifdef NAMES_HAVE_UNDERSCORE
+ *namestring == '_'
+ && namestring[1] == SYMBOL_NAME (sym)[0]
+ &&
+ !strcmp (namestring + 2, SYMBOL_NAME (sym) + 1)
+#else /* NAMES_HAVE_UNDERSCORE */
+ namestring[0] == SYMBOL_NAME (sym)[0]
+ &&
+ !strcmp (namestring + 1, SYMBOL_NAME (sym) + 1)
+#endif /* NAMES_HAVE_UNDERSCORE */
+ )
+ {
+ if (prev)
+ SYMBOL_VALUE (prev) = SYMBOL_VALUE (sym);
+ else
+ global_sym_chain[hash]
+ = (struct symbol *) SYMBOL_VALUE (sym);
+ if (SYMBOL_CLASS (sym) == LOC_BLOCK)
+ fix_common_block (sym, bufp->n_value);
+ else
+ SYMBOL_VALUE (sym) = bufp->n_value;
+ if (prev)
+ sym = (struct symbol *) SYMBOL_VALUE (prev);
+ else
+ sym = global_sym_chain[hash];
+
+ used_up = 1;
+ }
+ else
+ {
+ prev = sym;
+ sym = (struct symbol *) SYMBOL_VALUE (sym);
+ }
+ }
+ }
+
+ /* Defined global or text symbol: record as a misc function
+ if it didn't give its address to a debugger symbol above. */
+ if (type <= (N_TYPE | N_EXT)
+ && type != N_EXT
+ && ! used_up)
+ record_misc_function (namestring, bufp->n_value,
+ bufp->n_type);
+#endif /* 0 */
+ }
+ }
+
+ if (last_source_file)
+ end_symtab (text_addr + text_size);
+
+ fclose (stream);
+}
+
+/* C++:
+ This function allows the addition of incrementally linked object files.
+ Since this has a fair amount of code in common with symbol_file_command,
+ it might be worthwhile to consolidate things, as was done with
+ read_dbx_symtab and condense_misc_bunches. */
+
+void
+add_file_command (arg_string)
+ char* arg_string;
+{
+ register int desc;
+ DECLARE_FILE_HEADERS;
+ struct nlist *nlist;
+ char *stringtab;
+ long buffer;
+ register int val;
+ extern void close ();
+ struct cleanup *old_chain;
+ struct symtab *symseg;
+ struct stat statbuf;
+ char *name;
+ unsigned text_addr;
+
+ if (arg_string == 0)
+ error ("add-file takes a file name and an address");
+
+ arg_string = tilde_expand (arg_string);
+ make_cleanup (free, arg_string);
+
+ for( ; *arg_string == ' '; arg_string++ );
+ name = arg_string;
+ for( ; *arg_string && *arg_string != ' ' ; arg_string++ );
+ *arg_string++ = (char) 0;
+
+ if (name[0] == 0)
+ error ("add-file takes a file name and an address");
+
+ text_addr = parse_and_eval_address (arg_string);
+
+ dont_repeat ();
+
+ if (!query ("add symbol table from filename \"%s\" at text_addr = 0x%x\n",
+ name, text_addr))
+ error ("Not confirmed.");
+
+ desc = open (name, O_RDONLY);
+ if (desc < 0)
+ perror_with_name (name);
+
+ old_chain = make_cleanup (close, desc);
+
+ READ_FILE_HEADERS (desc, name);
+
+ if (NUMBER_OF_SYMBOLS == 0)
+ {
+ printf ("%s does not have a symbol-table.\n", name);
+ fflush (stdout);
+ return;
+ }
+
+ printf ("Reading symbol data from %s...", name);
+ fflush (stdout);
+
+ /* Now read the string table, all at once. */
+ val = lseek (desc, STRING_TABLE_OFFSET, 0);
+ if (val < 0)
+ perror_with_name (name);
+ if (stat (name, &statbuf) < 0)
+ perror_with_name (name);
+ READ_STRING_TABLE_SIZE (buffer);
+ if (buffer >= 0 && buffer < statbuf.st_size)
+ {
+#ifdef BROKEN_LARGE_ALLOCA
+ stringtab = (char *) xmalloc (buffer);
+ make_cleanup (free, stringtab);
+#else
+ stringtab = (char *) alloca (buffer);
+#endif
+ }
+ else
+ stringtab = NULL;
+ if (stringtab == NULL)
+ error ("ridiculous string table size: %d bytes", buffer);
+
+ /* Usually READ_STRING_TABLE_SIZE will have shifted the file pointer.
+ Occaisionally, it won't. */
+ val = lseek (desc, STRING_TABLE_OFFSET, 0);
+ if (val < 0)
+ perror_with_name (name);
+ val = myread (desc, stringtab, buffer);
+ if (val < 0)
+ perror_with_name (name);
+
+ /* Symsegs are no longer supported by GDB. Setting symseg_chain to
+ 0 is easier than finding all the symseg code and eliminating it. */
+ symseg_chain = 0;
+
+ /* Position to read the symbol table. Do not read it all at once. */
+ val = lseek (desc, SYMBOL_TABLE_OFFSET, 0);
+ if (val < 0)
+ perror_with_name (name);
+
+ init_misc_functions ();
+ make_cleanup (discard_misc_bunches, 0);
+ init_header_files ();
+ make_cleanup (free_header_files, 0);
+ free_pendings = 0;
+ pending_blocks = 0;
+ file_symbols = 0;
+ global_symbols = 0;
+ make_cleanup (really_free_pendings, 0);
+
+ read_addl_syms (desc, stringtab, NUMBER_OF_SYMBOLS, text_addr,
+ SIZE_OF_TEXT_SEGMENT);
+
+
+ /* Sort symbols alphabetically within each block. */
+
+ sort_syms ();
+
+ /* Go over the misc functions and install them in vector. */
+
+ condense_addl_misc_bunches (1);
+
+ /* Don't allow char * to have a typename (else would get caddr_t.) */
+
+ TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
+
+ do_cleanups (old_chain);
+
+ /* Free the symtabs made by read_symsegs, but not their contents,
+ which have been copied into symtabs on symtab_list. */
+ while (symseg_chain)
+ {
+ register struct symtab *s = symseg_chain->next;
+ free (symseg_chain);
+ symseg_chain = s;
+ }
+
+ printf ("done.\n");
+ fflush (stdout);
+}
+
+/* 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. */
+
+static void
+read_type_number (pp, typenums)
+ register char **pp;
+ register int *typenums;
+{
+ if (**pp == '(')
+ {
+ (*pp)++;
+ typenums[0] = read_number (pp, ',');
+ typenums[1] = read_number (pp, ')');
+ }
+ else
+ {
+ typenums[0] = 0;
+ typenums[1] = read_number (pp, 0);
+ }
+}
+
+
+
+static struct symbol *
+define_symbol (value, string, desc)
+ int value;
+ char *string;
+ int desc;
+{
+ register struct symbol *sym
+ = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol));
+ char *p = (char *) index (string, ':');
+ int deftype;
+ register int i;
+
+ /* Ignore syms with empty names. */
+ if (string[0] == 0)
+ return 0;
+
+ /* Ignore old-style symbols from cc -go */
+ if (p == 0)
+ return 0;
+
+ SYMBOL_NAME (sym)
+ = (char *) obstack_alloc (symbol_obstack, ((p - string) + 1));
+ /* Open-coded bcopy--saves function call time. */
+ {
+ register char *p1 = string;
+ register char *p2 = SYMBOL_NAME (sym);
+ while (p1 != p)
+ *p2++ = *p1++;
+ *p2++ = '\0';
+ }
+ p++;
+ /* Determine the type of name being defined. */
+ if ((*p >= '0' && *p <= '9') || *p == '(')
+ deftype = 'l';
+ else
+ deftype = *p++;
+
+ /* 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 (deftype == 'c')
+ {
+ if (*p++ != '=')
+ error ("Invalid symbol data at symtab pos %d.", symnum);
+ switch (*p++)
+ {
+ case 'r':
+ {
+ double d = atof (p);
+ char *value;
+
+ SYMBOL_TYPE (sym) = builtin_type_double;
+ value = (char *) obstack_alloc (symbol_obstack, sizeof (double));
+ bcopy (&d, value, sizeof (double));
+ SYMBOL_VALUE_BYTES (sym) = value;
+ SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+ }
+ break;
+ case 'i':
+ {
+ SYMBOL_TYPE (sym) = builtin_type_int;
+ SYMBOL_VALUE (sym) = atoi (p);
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ }
+ break;
+ case 'e':
+ /* 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,;"). */
+ {
+ int typenums[2];
+
+ read_type_number (&p, typenums);
+ if (*p++ != ',')
+ error ("Invalid symbol data: no comma in enum const symbol");
+
+ SYMBOL_TYPE (sym) = *dbx_lookup_type (typenums);
+ SYMBOL_VALUE (sym) = atoi (p);
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ }
+ break;
+ default:
+ error ("Invalid symbol data at symtab pos %d.", symnum);
+ }
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ return sym;
+ }
+
+ /* Now usually comes a number that says which data type,
+ and possibly more stuff to define the type
+ (all of which is handled by read_type) */
+
+ if (deftype == 'p' && *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)));
+ }
+ else
+ {
+ struct type *type = read_type (&p);
+
+ if ((deftype == 'F' || deftype == 'f')
+ && TYPE_CODE (type) != TYPE_CODE_FUNC)
+ SYMBOL_TYPE (sym) = lookup_function_type (type);
+ else
+ SYMBOL_TYPE (sym) = type;
+ }
+
+ switch (deftype)
+ {
+ case 'f':
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'F':
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &global_symbols);
+ break;
+
+ 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. */
+ i = hashname (SYMBOL_NAME (sym));
+ SYMBOL_VALUE (sym) = (int) 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 'l':
+ SYMBOL_CLASS (sym) = LOC_LOCAL;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'p':
+ SYMBOL_CLASS (sym) = LOC_ARG;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+
+ /* If it's gcc compiled, if it says `short', believe it. */
+ if (processing_gcc_compilation || BELIEVE_PCC_PROMOTION)
+ break;
+
+#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). Note that
+ this is only different from the BELIEVE_PCC_PROMOTION
+ case on big-endian machines.
+
+ 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 no 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 (0 == SYMBOL_VALUE (sym) % sizeof (int))
+ {
+ if (SYMBOL_TYPE (sym) == builtin_type_char
+ || SYMBOL_TYPE (sym) == builtin_type_unsigned_char)
+ SYMBOL_VALUE (sym) += 3;
+ else if (SYMBOL_TYPE (sym) == builtin_type_short
+ || SYMBOL_TYPE (sym) == builtin_type_unsigned_short)
+ SYMBOL_VALUE (sym) += 2;
+ }
+ break;
+
+#else /* no BELIEVE_PCC_PROMOTION_TYPE. */
+
+ /* If PCC says a parameter is a short or a char,
+ it is really an int. */
+ if (SYMBOL_TYPE (sym) == builtin_type_char
+ || SYMBOL_TYPE (sym) == builtin_type_short)
+ SYMBOL_TYPE (sym) = builtin_type_int;
+ else if (SYMBOL_TYPE (sym) == builtin_type_unsigned_char
+ || SYMBOL_TYPE (sym) == builtin_type_unsigned_short)
+ SYMBOL_TYPE (sym) = builtin_type_unsigned_int;
+ break;
+
+#endif /* no BELIEVE_PCC_PROMOTION_TYPE. */
+
+ case 'P':
+ SYMBOL_CLASS (sym) = LOC_REGPARM;
+ SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (value);
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'r':
+/* XXX */
+#ifdef sparc
+{
+ struct symbol *s0;
+
+ /*
+ * If we see a parm decl immediately followed by a reg decl of
+ * the same name (and in the same block), we change it to a single
+ * instance of a reg parm. Sun's cc will generate these.
+ */
+ if (local_symbols &&
+ (s0 = local_symbols->symbol[local_symbols->nsyms - 1]) &&
+ SYMBOL_CLASS(s0) == LOC_ARG &&
+ strcmp(SYMBOL_NAME(s0), SYMBOL_NAME(sym)) == 0) {
+ SYMBOL_CLASS (s0) = LOC_REGPARM;
+ SYMBOL_VALUE (s0) = STAB_REG_TO_REGNUM (value);
+ SYMBOL_NAMESPACE (s0) = VAR_NAMESPACE;
+ return s0;
+ }
+}
+#endif
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (value);
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'S':
+ /* Static symbol at top level of file */
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 't':
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0
+ && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym)) =
+ obsavestring (SYMBOL_NAME (sym),
+ strlen (SYMBOL_NAME (sym)));
+ /* 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. */
+ else if ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)
+ && TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)))
+ {
+ int i;
+ for (i = TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)); i > 0; i--)
+ if (TYPE_FIELD_NAME (SYMBOL_TYPE (sym), i - 1) == 0)
+ TYPE_FIELD_NAME (SYMBOL_TYPE (sym), i - 1) =
+ TYPE_NAME (TYPE_BASECLASS (SYMBOL_TYPE (sym), i));
+ }
+
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'T':
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0
+ && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym))
+ = obconcat ("",
+ (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM
+ ? "enum "
+ : (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+ ? "struct " : "union ")),
+ SYMBOL_NAME (sym));
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'V':
+ /* Static symbol of local scope */
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'v':
+ /* Reference parameter */
+ SYMBOL_CLASS (sym) = LOC_REF_ARG;
+ SYMBOL_VALUE (sym) = value;
+ 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_CLASS (sym) = LOC_LOCAL;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ default:
+ error ("Invalid symbol data: unknown symbol-type code `%c' at symtab pos %d.", deftype, symnum);
+ }
+ return sym;
+}
+
+/* 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. */
+static void
+add_undefined_type (type)
+ struct type *type;
+{
+ if (undef_types_length == undef_types_allocated)
+ {
+ undef_types_allocated *= 2;
+ undef_types = (struct type **)
+ xrealloc (undef_types,
+ undef_types_allocated * sizeof (struct type *));
+ }
+ undef_types[undef_types_length++] = type;
+}
+
+/* Add here something to go through each undefined type, see if it's
+ still undefined, and do a full lookup if so. */
+static void
+cleanup_undefined_types ()
+{
+ struct type **type, *ntype;
+ struct symbol *sym;
+
+ for (type = undef_types; type < undef_types + undef_types_length; type++)
+ {
+ struct type *ntype = 0;
+ /* Reasonable test to see if it's been defined since. */
+ if (TYPE_NFIELDS (*type) == 0)
+ {
+ struct pending *ppt;
+ int i;
+ /* Name of the type, without "struct" or "union" */
+ char *typename = TYPE_NAME (*type);
+
+ if (!strncmp (typename, "struct ", 7))
+ typename += 7;
+ if (!strncmp (typename, "union ", 6))
+ typename += 6;
+
+ 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))
+ && !strcmp (SYMBOL_NAME (sym), typename))
+ bcopy (SYMBOL_TYPE (sym), *type, sizeof (struct type));
+ }
+ }
+ else
+ /* It has been defined; don't mark it as a stub. */
+ TYPE_FLAGS (*type) &= ~TYPE_FLAG_STUB;
+ }
+ undef_types_length = 0;
+}
+
+
+
+/* Read a dbx type reference or definition;
+ return the type that is meant.
+ This can be just a number, in which case it references
+ a type already defined and placed in type_vector.
+ Or the number can be followed by an =, in which case
+ it means to define a new type according to the text that
+ follows the =. */
+
+static
+struct type *
+read_type (pp)
+ register char **pp;
+{
+ register struct type *type = 0;
+ register int n;
+ struct type *type1;
+ int typenums[2];
+ int xtypenums[2];
+ char *tmpc;
+
+ /* 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 == '(')
+ {
+ read_type_number (pp, typenums);
+
+ /* Detect random reference to type not yet defined.
+ Allocate a type object but leave it zeroed. */
+ if (**pp != '=')
+ return dbx_alloc_type (typenums);
+
+ *pp += 2;
+ }
+ 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 += 1;
+ }
+
+ switch ((*pp)[-1])
+ {
+ case 'x':
+ {
+ enum type_code code;
+
+ /* Used to index through file_symbols. */
+ struct pending *ppt;
+ int i;
+
+ /* Name including "struct", etc. */
+ char *type_name;
+
+ /* Name without "struct", etc. */
+ char *type_name_only;
+
+ {
+ char *prefix;
+ char *from, *to;
+
+ /* Set the type code according to the following letter. */
+ switch ((*pp)[0])
+ {
+ case 's':
+ code = TYPE_CODE_STRUCT;
+ prefix = "struct ";
+ break;
+ case 'u':
+ code = TYPE_CODE_UNION;
+ prefix = "union ";
+ break;
+ case 'e':
+ code = TYPE_CODE_ENUM;
+ prefix = "enum ";
+ break;
+ default:
+ error ("Bad type cross reference at symnum: %d.", symnum);
+ }
+
+ to = type_name = (char *)
+ obstack_alloc (symbol_obstack,
+ (strlen (prefix) +
+ ((char *) index (*pp, ':') - (*pp)) + 1));
+
+ /* Copy the prefix. */
+ from = prefix;
+ while (*to++ = *from++)
+ ;
+ to--;
+
+ type_name_only = to;
+
+ /* Copy the name. */
+ from = *pp + 1;
+ while ((*to++ = *from++) != ':')
+ ;
+ *--to = '\0';
+
+ /* Set the pointer ahead of the name which we just read. */
+ *pp = from;
+
+#if 0
+ /* The following hack is clearly wrong, because it doesn't
+ check whether we are in a baseclass. I tried to reproduce
+ the case that it is trying to fix, but I couldn't get
+ g++ to put out a cross reference to a basetype. Perhaps
+ it doesn't do it anymore. */
+ /* Note: for C++, the cross reference may be to a base type which
+ has not yet been seen. In this case, we skip to the comma,
+ which will mark the end of the base class name. (The ':'
+ at the end of the base class name will be skipped as well.)
+ But sometimes (ie. when the cross ref is the last thing on
+ the line) there will be no ','. */
+ from = (char *) index (*pp, ',');
+ if (from)
+ *pp = from;
+#endif /* 0 */
+ }
+
+ /* Now check to see whether the type has already been declared. */
+ /* This is necessary at least in the case where the
+ program says something like
+ struct foo bar[5];
+ The compiler puts out a cross-reference; we better find
+ set the length of the structure correctly so we can
+ set the length of the array. */
+ 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)
+ && !strcmp (SYMBOL_NAME (sym), type_name_only))
+ {
+ obstack_free (symbol_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);
+ TYPE_CODE (type) = code;
+ TYPE_NAME (type) = type_name;
+
+ TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+
+ add_undefined_type (type);
+ return type;
+ }
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '(':
+ (*pp)--;
+ read_type_number (pp, xtypenums);
+ type = *dbx_lookup_type (xtypenums);
+ if (type == 0)
+ type = builtin_type_void;
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case '*':
+ type1 = read_type (pp);
+ if (TYPE_POINTER_TYPE (type1))
+ {
+ type = TYPE_POINTER_TYPE (type1);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ }
+ else
+ {
+ type = dbx_alloc_type (typenums);
+ smash_to_pointer_type (type, type1);
+ }
+ break;
+
+ case '@':
+ {
+ struct type *domain = read_type (pp);
+ char c;
+ struct type *memtype;
+
+ if (*(*pp)++ != ',')
+ error ("invalid member type data format, at symtab pos %d.",
+ symnum);
+
+ memtype = read_type (pp);
+ type = dbx_alloc_type (typenums);
+ smash_to_member_type (type, domain, memtype);
+ }
+ break;
+
+ case '#':
+ {
+ struct type *domain = read_type (pp);
+ char c;
+ struct type *return_type;
+ struct type **args;
+
+ if (*(*pp)++ != ',')
+ error ("invalid member type data format, at symtab pos %d.",
+ symnum);
+
+ return_type = read_type (pp);
+ args = read_args (pp, ';');
+ type = dbx_alloc_type (typenums);
+ smash_to_method_type (type, domain, return_type, args);
+ }
+ break;
+
+ case '&':
+ type1 = read_type (pp);
+ if (TYPE_REFERENCE_TYPE (type1))
+ {
+ type = TYPE_REFERENCE_TYPE (type1);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ }
+ else
+ {
+ type = dbx_alloc_type (typenums);
+ smash_to_reference_type (type, type1);
+ }
+ break;
+
+ case 'f':
+ type1 = read_type (pp);
+ if (TYPE_FUNCTION_TYPE (type1))
+ {
+ type = TYPE_FUNCTION_TYPE (type1);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ }
+ else
+ {
+ type = dbx_alloc_type (typenums);
+ smash_to_function_type (type, type1);
+ }
+ break;
+
+ case 'r':
+ type = read_range_type (pp, typenums);
+ if (typenums[0] != -1)
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 'e':
+ type = dbx_alloc_type (typenums);
+ type = read_enum_type (pp, type);
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 's':
+ type = dbx_alloc_type (typenums);
+ type = read_struct_type (pp, type);
+ break;
+
+ case 'u':
+ type = dbx_alloc_type (typenums);
+ type = read_struct_type (pp, type);
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ break;
+
+ case 'a':
+ if (*(*pp)++ != 'r')
+ error ("Invalid symbol data: unrecognized type-code `a%c' %s %d.",
+ (*pp)[-1], "at symtab position", symnum);
+
+ type = dbx_alloc_type (typenums);
+ type = read_array_type (pp, type);
+ break;
+
+ default:
+ error ("Invalid symbol data: unrecognized type-code `%c' at symtab pos %d.",
+ (*pp)[-1], symnum);
+ }
+
+ if (type == 0)
+ abort ();
+
+#if 0
+ /* If this is an overriding temporary alteration for a header file's
+ contents, and this type number is unknown in the global definition,
+ put this type into the global definition at this type number. */
+ if (header_file_prev_index >= 0)
+ {
+ register struct type **tp
+ = explicit_lookup_type (header_file_prev_index, typenums[1]);
+ if (*tp == 0)
+ *tp = type;
+ }
+#endif
+ return type;
+}
+
+/* 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 *
+read_struct_type (pp, type)
+ char **pp;
+ register struct type *type;
+{
+ struct nextfield
+ {
+ struct nextfield *next;
+ int visibility;
+ struct field field;
+ };
+
+ struct next_fnfield
+ {
+ struct next_fnfield *next;
+ int visibility;
+ struct fn_field fn_field;
+ };
+
+ struct next_fnfieldlist
+ {
+ struct next_fnfieldlist *next;
+ struct fn_fieldlist fn_fieldlist;
+ };
+
+ register struct nextfield *list = 0;
+ struct nextfield *new;
+ int totalsize;
+ char *name;
+ register char *p;
+ int nfields = 0;
+ register int n;
+
+ register struct next_fnfieldlist *mainlist = 0;
+ int nfn_fields = 0;
+ int read_possible_virtual_info = 0;
+
+ if (TYPE_MAIN_VARIANT (type) == 0)
+ {
+ TYPE_MAIN_VARIANT (type) = type;
+ }
+
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+
+ /* First comes the total size in bytes. */
+
+ TYPE_LENGTH (type) = read_number (pp, 0);
+
+ /* C++: Now, if the class is a derived class, then the next character
+ will be a '!', followed by the number of base classes derived from.
+ Each element in the list contains visibility information,
+ the offset of this base class in the derived structure,
+ and then the base type. */
+ if (**pp == '!')
+ {
+ int i, n_baseclasses, offset;
+ struct type **baseclass_vec;
+ struct type *baseclass;
+ int via_public;
+
+ /* Nonzero if it is a virtual baseclass, i.e.,
+
+ struct A{};
+ struct B{};
+ struct 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. */
+ int via_virtual;
+
+ *pp += 1;
+
+ n_baseclasses = read_number (pp, ',');
+ baseclass_vec = (struct type **)
+ obstack_alloc (symbol_obstack,
+ (n_baseclasses) * sizeof (struct type **)) - 1;
+
+ for (i = 1; i <= n_baseclasses; i++)
+ {
+ if (**pp == '\\')
+ *pp = next_symbol_text ();
+
+ switch (*(*pp)++)
+ {
+ case '0':
+ via_virtual = 0;
+ break;
+ case '1':
+ via_virtual = 1;
+ break;
+ default:
+ error ("Invalid symbol data: bad visibility format at symtab pos %d",
+ symnum);
+ }
+
+ switch (*(*pp)++)
+ {
+ case '0':
+ via_public = 0;
+ break;
+ case '2':
+ via_public = 1;
+ break;
+ default:
+ error ("Invalid symbol data: bad visibility format at symtab pos %d.",
+ symnum);
+ }
+
+ /* Offset of the portion of the object corresponding to
+ this baseclass. Always zero in the absence of
+ multiple inheritance. */
+ offset = read_number (pp, ',');
+ baseclass = read_type (pp);
+ *pp += 1; /* skip trailing ';' */
+
+ if (offset != 0)
+ {
+ static int error_printed = 0;
+
+ if (!error_printed)
+ {
+ fprintf (stderr,
+"\nWarning: GDB has limited understanding of multiple inheritance...");
+ error_printed = 1;
+ }
+ offset = 0;
+ }
+
+ baseclass_vec[i] = lookup_basetype_type (baseclass, offset, via_virtual, via_public);
+
+ /* Since lookup_basetype_type can copy the type,
+ it might copy a stub type (complete with stub flag).
+ If so, we need to add it to the list of undefined types
+ to clean up later. Even if lookup_basetype_type
+ didn't copy the type, adding it to the undefined list
+ will not do any harm. */
+ if (TYPE_FLAGS(baseclass_vec[i]) & TYPE_FLAG_STUB)
+ add_undefined_type (baseclass_vec[i]);
+
+ /* Make this baseclass visible for structure-printing purposes. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+ list->field.type = baseclass_vec[i];
+ list->field.name = TYPE_NAME (baseclass_vec[i]);
+ list->field.bitpos = offset;
+ list->field.bitsize = 0; /* this should be an unpacked field! */
+ nfields++;
+ }
+ TYPE_N_BASECLASSES (type) = n_baseclasses;
+ TYPE_BASECLASSES (type) = baseclass_vec;
+ }
+
+ /* Now come the fields, as NAME:?TYPENUM,BITPOS,BITSIZE; for each one.
+ 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 `?' is a placeholder for one of '+' (public visibility),
+ '0' (protected visibility), and '-' (private visibility). */
+
+ /* We better set p right now, in case there are no fields at all... */
+ p = *pp;
+
+ while (**pp != ';')
+ {
+ int visibility;
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (**pp == '\\') *pp = next_symbol_text ();
+
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ /* Get the field name. */
+ p = *pp;
+ while (*p != ':') p++;
+ list->field.name = obsavestring (*pp, p - *pp);
+
+ /* C++: Check to see if we have hit the methods yet. */
+ if (p[1] == ':')
+ break;
+
+ *pp = p + 1;
+
+ /* This means we have a visibility for a field coming. */
+ if (**pp == '/')
+ {
+ switch (*++*pp)
+ {
+ case '0':
+ visibility = 0;
+ *pp += 1;
+ break;
+
+ case '1':
+ visibility = 1;
+ *pp += 1;
+ break;
+
+ case '2':
+ visibility = 2;
+ *pp += 1;
+ break;
+ }
+ }
+ /* else normal dbx-style format. */
+
+ list->field.type = read_type (pp);
+ if (**pp == ':')
+ {
+ list->field.bitpos = (long)-1;
+ p = ++(*pp);
+ while (*p != ';') p++;
+ list->field.bitsize = (long) savestring (*pp, p - *pp);
+ *pp = p + 1;
+ nfields++;
+ continue;
+ }
+ else if (**pp != ',')
+ error ("Invalid symbol data: bad structure-type format at symtab pos %d.",
+ symnum);
+ (*pp)++; /* Skip the comma. */
+ list->field.bitpos = read_number (pp, ',');
+ list->field.bitsize = read_number (pp, ';');
+
+#if 0
+ /* This is wrong because this is identical to the symbols
+ produced for GCC 0-size arrays. For example:
+ typedef union {
+ int num;
+ char str[0];
+ } foo;
+ The code which dumped core in such circumstances should be
+ fixed not to dump core. */
+
+ /* g++ -g0 can put out bitpos & bitsize zero for a static
+ field. This does not give us any way of getting its
+ class, so we can't know its name. But we can just
+ ignore the field so we don't dump core and other nasty
+ stuff. */
+ if (list->field.bitpos == 0
+ && list->field.bitsize == 0)
+ {
+ /* Have we given the warning yet? */
+ static int warning_given = 0;
+
+ /* Only give the warning once, no matter how many class
+ variables there are. */
+ if (!warning_given)
+ {
+ warning_given = 1;
+ fprintf_filtered (stderr, "\n\
+Warning: DBX-style class variable debugging information encountered.\n\
+You seem to have compiled your program with \
+\"g++ -g0\" instead of \"g++ -g\".\n\
+Therefore GDB will not know about your class variables.\n\
+");
+ }
+
+ /* Ignore this field. */
+ list = list->next;
+ }
+ else
+#endif /* 0 */
+ {
+ /* 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 (list->field.type) != TYPE_CODE_INT
+ && TYPE_CODE (list->field.type) != TYPE_CODE_ENUM)
+ list->field.bitsize = 0;
+ if ((list->field.bitsize == 8 * TYPE_LENGTH (list->field.type)
+ || (TYPE_CODE (list->field.type) == TYPE_CODE_ENUM
+ && (list->field.bitsize
+ == 8 * TYPE_LENGTH (builtin_type_int))
+ )
+ )
+ &&
+ list->field.bitpos % 8 == 0)
+ list->field.bitsize = 0;
+ nfields++;
+ }
+ }
+
+ /* Now come the method fields, as NAME::methods
+ where each method is of the form TYPENUM,ARGS,...:PHYSNAME;
+ At the end, we see a semicolon instead of a field.
+
+ For the case of overloaded operators, the format is
+ OPERATOR::*.methods, where OPERATOR is the string "operator",
+ `*' holds the place for an operator name (such as `+=')
+ and `.' marks the end of the operator name. */
+ if (p[1] == ':')
+ {
+ /* Now, read in the methods. To simplify matters, we
+ "unread" the name that has been read, so that we can
+ start from the top. */
+
+ p = *pp;
+
+ /* chill the list of fields: the last entry (at the head)
+ is a partially constructed entry which we now scrub. */
+ list = list->next;
+
+ /* For each list of method lists... */
+ do
+ {
+ int i;
+ struct next_fnfield *sublist = 0;
+ struct fn_field *fn_fields = 0;
+ int length = 0;
+ struct next_fnfieldlist *new_mainlist =
+ (struct next_fnfieldlist *)alloca (sizeof (struct next_fnfieldlist));
+
+ /* read in the name. */
+ while (*p != ':') p++;
+ if ((*pp)[0] == 'o' && (*pp)[1] == 'p' && (*pp)[2] == '$')
+ {
+ static char opname[] = "operator";
+ char *o = opname + strlen(opname);
+
+ /* Skip past '::'. */
+ p += 2;
+ while (*p != '.')
+ *o++ = *p++;
+ new_mainlist->fn_fieldlist.name = savestring (opname, o - opname);
+ /* Skip past '.' */
+ *pp = p + 1;
+ }
+ else
+ {
+ i = 0;
+ new_mainlist->fn_fieldlist.name = savestring (*pp, p - *pp);
+ /* Skip past '::'. */
+ *pp = p + 2;
+ }
+
+ do
+ {
+ struct next_fnfield *new_sublist =
+ (struct next_fnfield *)alloca (sizeof (struct next_fnfield));
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (**pp == '\\') *pp = next_symbol_text ();
+
+ new_sublist->fn_field.type = read_type (pp);
+ if (**pp != ':')
+ error ("invalid symtab info for method at symbol number %d.",
+ symnum);
+ *pp += 1;
+ new_sublist->fn_field.args =
+ TYPE_ARG_TYPES (new_sublist->fn_field.type);
+ p = *pp;
+ while (*p != ';') p++;
+ new_sublist->fn_field.physname = savestring (*pp, p - *pp);
+ *pp = p + 1;
+ new_sublist->visibility = *(*pp)++ - '0';
+ if (**pp == '\\') *pp = next_symbol_text ();
+
+ switch (*(*pp)++)
+ {
+ case '*':
+ /* virtual member function, followed by index. */
+ new_sublist->fn_field.voffset = read_number (pp, ';') + 1;
+ break;
+ case '?':
+ /* static member function. */
+ new_sublist->fn_field.voffset = 1;
+ break;
+ default:
+ /* **pp == '.'. */
+ /* normal member function. */
+ new_sublist->fn_field.voffset = 0;
+ break;
+ }
+
+ new_sublist->next = sublist;
+ sublist = new_sublist;
+ length++;
+ }
+ while (**pp != ';');
+
+ *pp += 1;
+
+ new_mainlist->fn_fieldlist.fn_fields =
+ (struct fn_field *) obstack_alloc (symbol_obstack,
+ sizeof (struct fn_field) * length);
+ TYPE_FN_PRIVATE_BITS (new_mainlist->fn_fieldlist) =
+ (int *) obstack_alloc (symbol_obstack,
+ sizeof (int) * (1 + (length >> 5)));
+
+ TYPE_FN_PROTECTED_BITS (new_mainlist->fn_fieldlist) =
+ (int *) obstack_alloc (symbol_obstack,
+ sizeof (int) * (1 + (length >> 5)));
+
+ for (i = length; sublist; sublist = sublist->next)
+ {
+ new_mainlist->fn_fieldlist.fn_fields[--i] = sublist->fn_field;
+ if (sublist->visibility == 0)
+ B_SET (new_mainlist->fn_fieldlist.private_fn_field_bits, i);
+ else if (sublist->visibility == 1)
+ B_SET (new_mainlist->fn_fieldlist.protected_fn_field_bits, i);
+ }
+
+ new_mainlist->fn_fieldlist.length = length;
+ new_mainlist->next = mainlist;
+ mainlist = new_mainlist;
+ nfn_fields++;
+ }
+ while (**pp != ';');
+ }
+
+ *pp += 1;
+
+ /* Now create the vector of fields, and record how big it is. */
+
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack,
+ sizeof (struct field) * nfields);
+ TYPE_FIELD_PRIVATE_BITS (type) =
+ (int *) obstack_alloc (symbol_obstack,
+ sizeof (int) * (1 + (nfields >> 5)));
+ TYPE_FIELD_PROTECTED_BITS (type) =
+ (int *) obstack_alloc (symbol_obstack,
+ sizeof (int) * (1 + (nfields >> 5)));
+
+ TYPE_NFN_FIELDS (type) = nfn_fields;
+ TYPE_NFN_FIELDS_TOTAL (type) = nfn_fields;
+
+ {
+ int i;
+ for (i = 1; i <= TYPE_N_BASECLASSES (type); ++i)
+ TYPE_NFN_FIELDS_TOTAL (type) +=
+ TYPE_NFN_FIELDS_TOTAL (TYPE_BASECLASS (type, i));
+ }
+
+ TYPE_FN_FIELDLISTS (type) =
+ (struct fn_fieldlist *) obstack_alloc (symbol_obstack,
+ sizeof (struct fn_fieldlist) * nfn_fields);
+
+ /* Copy the saved-up fields into the field vector. */
+
+ for (n = nfields; list; list = list->next)
+ {
+ TYPE_FIELD (type, --n) = list->field;
+ if (list->visibility == 0)
+ SET_TYPE_FIELD_PRIVATE (type, n);
+ else if (list->visibility == 1)
+ SET_TYPE_FIELD_PROTECTED (type, n);
+ }
+
+ for (n = nfn_fields; mainlist; mainlist = mainlist->next)
+ TYPE_FN_FIELDLISTS (type)[--n] = mainlist->fn_fieldlist;
+
+ if (**pp == '~')
+ {
+ *pp += 1;
+
+ if (**pp == '=')
+ {
+ TYPE_FLAGS (type)
+ |= TYPE_FLAG_HAS_CONSTRUCTOR | TYPE_FLAG_HAS_DESTRUCTOR;
+ *pp += 1;
+ }
+ else if (**pp == '+')
+ {
+ TYPE_FLAGS (type) |= TYPE_FLAG_HAS_CONSTRUCTOR;
+ *pp += 1;
+ }
+ else if (**pp == '-')
+ {
+ TYPE_FLAGS (type) |= TYPE_FLAG_HAS_DESTRUCTOR;
+ *pp += 1;
+ }
+
+ /* Read either a '%' or the final ';'. */
+ if (*(*pp)++ == '%')
+ {
+ /* Now we must record the virtual function table pointer's
+ field information. */
+
+ struct type *t;
+ int i;
+
+ t = read_type (pp);
+ p = (*pp)++;
+ while (*p != ';') p++;
+ TYPE_VPTR_BASETYPE (type) = t;
+ if (type == t)
+ {
+ if (TYPE_FIELD_NAME (t, 0) == 0)
+ TYPE_VPTR_FIELDNO (type) = i = 0;
+ else for (i = TYPE_NFIELDS (t) - 1; i >= 0; --i)
+ if (! strncmp (TYPE_FIELD_NAME (t, i), *pp,
+ strlen (TYPE_FIELD_NAME (t, i))))
+ {
+ TYPE_VPTR_FIELDNO (type) = i;
+ break;
+ }
+ if (i < 0)
+ error ("virtual function table field not found");
+ }
+ else
+ TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, 1));
+ *pp = p + 1;
+ }
+ else
+ {
+ TYPE_VPTR_BASETYPE (type) = 0;
+ TYPE_VPTR_FIELDNO (type) = -1;
+ }
+ }
+ else
+ {
+ TYPE_VPTR_BASETYPE (type) = 0;
+ TYPE_VPTR_FIELDNO (type) = -1;
+ }
+
+ 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)
+ register char **pp;
+ register struct type *type;
+{
+ struct type *index_type, *element_type, *range_type;
+ int lower, upper;
+ int adjustable = 0;
+
+ /* Format of an array type:
+ "ar<index type>;lower;upper;<array_contents_type>". Put code in
+ to handle this.
+
+ Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
+ for these, produce a type like float[][]. */
+
+ index_type = read_type (pp);
+ if (*(*pp)++ != ';')
+ error ("Invalid symbol data; improper format of array type decl.");
+
+ if (!(**pp >= '0' && **pp <= '9'))
+ {
+ *pp += 1;
+ adjustable = 1;
+ }
+ lower = read_number (pp, ';');
+
+ if (!(**pp >= '0' && **pp <= '9'))
+ {
+ *pp += 1;
+ adjustable = 1;
+ }
+ upper = read_number (pp, ';');
+
+ element_type = read_type (pp);
+
+ if (adjustable)
+ {
+ lower = 0;
+ upper = -1;
+ }
+
+ {
+ /* Create range type. */
+ range_type = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+ TYPE_CODE (range_type) = TYPE_CODE_RANGE;
+ TYPE_TARGET_TYPE (range_type) = index_type;
+
+ /* This should never be needed. */
+ TYPE_LENGTH (range_type) = sizeof (int);
+
+ TYPE_NFIELDS (range_type) = 2;
+ TYPE_FIELDS (range_type) =
+ (struct field *) obstack_alloc (symbol_obstack,
+ 2 * sizeof (struct field));
+ TYPE_FIELD_BITPOS (range_type, 0) = lower;
+ TYPE_FIELD_BITPOS (range_type, 1) = upper;
+ }
+
+ TYPE_CODE (type) = TYPE_CODE_ARRAY;
+ TYPE_TARGET_TYPE (type) = element_type;
+ TYPE_LENGTH (type) = (upper - lower + 1) * TYPE_LENGTH (element_type);
+ TYPE_NFIELDS (type) = 1;
+ TYPE_FIELDS (type) =
+ (struct field *) obstack_alloc (symbol_obstack,
+ sizeof (struct field));
+ TYPE_FIELD_TYPE (type, 0) = range_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)
+ register char **pp;
+ register struct type *type;
+{
+ 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;
+
+ if (within_function)
+ symlist = &local_symbols;
+ else
+ symlist = &file_symbols;
+ osyms = *symlist;
+ o_nsyms = osyms ? osyms->nsyms : 0;
+
+ /* Read the value-names and their values.
+ The input syntax is NAME:VALUE,NAME:VALUE, and so on.
+ A semicolon or comman instead of a NAME means the end. */
+ while (**pp && **pp != ';' && **pp != ',')
+ {
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (**pp == '\\') *pp = next_symbol_text ();
+
+ p = *pp;
+ while (*p != ':') p++;
+ name = obsavestring (*pp, p - *pp);
+ *pp = p + 1;
+ n = read_number (pp, ',');
+
+ sym = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol));
+ bzero (sym, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = name;
+ 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) = sizeof (int);
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ TYPE_NFIELDS (type) = nsyms;
+ TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack, 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++)
+ {
+ struct symbol *sym = syms->symbol[j];
+ SYMBOL_TYPE (sym) = type;
+ TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (sym);
+ TYPE_FIELD_VALUE (type, n) = 0;
+ TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (sym);
+ TYPE_FIELD_BITSIZE (type, n++) = 0;
+ }
+ if (syms == osyms)
+ break;
+ }
+
+ return type;
+}
+
+#define MAX_OF_TYPE(t) ((1 << (sizeof (t) - 1)) - 1)
+#define MIN_OF_TYPE(t) (-(1 << (sizeof (t) - 1)))
+
+static struct type *
+read_range_type (pp, typenums)
+ char **pp;
+ int typenums[2];
+{
+ 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. */
+ read_type_number (pp, rangenums);
+ 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. */
+ read_huge_number (pp, ';', &n2, &n2bits);
+ read_huge_number (pp, ';', &n3, &n3bits);
+
+ if (n2bits == -1 || n3bits == -1)
+ error ("Unrecognized type range %s.", pp);
+
+ if (n2bits != 0 || n3bits != 0)
+#ifdef LONG_LONG
+ {
+ char got_signed = 0;
+ char got_unsigned = 0;
+ /* Number of bits in the type. */
+ int nbits;
+
+ /* 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 fro <large number> to <large number>-1 is a large signed
+ integral type. */
+ else if (n2bits != 0 && n3bits != 0 && n2bits == n3bits + 1)
+ {
+ got_signed = 1;
+ nbits = n2bits;
+ }
+
+ /* Check for "long long". */
+ if (got_signed && nbits == CHAR_BIT * sizeof (long long))
+ return builtin_type_long_long;
+ if (got_unsigned && nbits == CHAR_BIT * sizeof (long long))
+ return builtin_type_unsigned_long_long;
+
+ error ("Large type isn't a long long.");
+ }
+#else /* LONG_LONG */
+ error ("Type long long not supported on this machine.");
+#endif
+
+ /* A type defined as a subrange of itself, with bounds both 0, is void. */
+ if (self_subrange && n2 == 0 && n3 == 0)
+ return builtin_type_void;
+
+ /* 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!
+ We don't have complex types, so we would lose on all fortran files!
+ So return type `double' for all of those. It won't work right
+ for the complex values, but at least it makes the file loadable. */
+
+ if (n3 == 0 && n2 > 0)
+ {
+ if (n2 == sizeof (float))
+ return builtin_type_float;
+ return builtin_type_double;
+ }
+
+ /* If the upper bound is -1, it must really be an unsigned int. */
+
+ else if (n2 == 0 && n3 == -1)
+ {
+ if (sizeof (int) == sizeof (long))
+ return builtin_type_unsigned_int;
+ else
+ return builtin_type_unsigned_long;
+ }
+
+ /* 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 builtin_type_char;
+
+ /* Assumptions made here: Subrange of self is equivalent to subrange
+ of int. */
+ else if (n2 == 0
+ && (self_subrange ||
+ *dbx_lookup_type (rangenums) == builtin_type_int))
+ {
+ /* an unsigned type */
+ if (n3 == UINT_MAX)
+ return builtin_type_unsigned_int;
+ if (n3 == ULONG_MAX)
+ return builtin_type_unsigned_long;
+ if (n3 == USHRT_MAX)
+ return builtin_type_unsigned_short;
+ if (n3 == UCHAR_MAX)
+ return builtin_type_unsigned_char;
+ }
+#ifdef LONG_LONG
+ else if (n3 == 0 && n2 == -sizeof (long long))
+ return builtin_type_long_long;
+#endif
+ else if (n2 == -n3 -1)
+ {
+ /* a signed type */
+ if (n3 == INT_MAX)
+ return builtin_type_int;
+ if (n3 == LONG_MAX)
+ return builtin_type_long;
+ if (n3 == SHRT_MAX)
+ return builtin_type_short;
+ if (n3 == CHAR_MAX)
+ return builtin_type_char;
+ }
+
+ /* 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)
+ error ("Type defined as subrange of itself: %s.", pp);
+
+ result_type = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+ bzero (result_type, sizeof (struct type));
+
+ TYPE_TARGET_TYPE (result_type) = (self_subrange ?
+ builtin_type_int :
+ *dbx_lookup_type(rangenums));
+
+ /* We have to figure out how many bytes it takes to hold this
+ range type. I'm going to assume that anything that is pushing
+ the bounds of a long was taken care of above. */
+ if (n2 >= MIN_OF_TYPE(char) && n3 <= MAX_OF_TYPE(char))
+ TYPE_LENGTH (result_type) = 1;
+ else if (n2 >= MIN_OF_TYPE(short) && n3 <= MAX_OF_TYPE(short))
+ TYPE_LENGTH (result_type) = sizeof (short);
+ else if (n2 >= MIN_OF_TYPE(int) && n3 <= MAX_OF_TYPE(int))
+ TYPE_LENGTH (result_type) = sizeof (int);
+ else if (n2 >= MIN_OF_TYPE(long) && n3 <= MAX_OF_TYPE(long))
+ TYPE_LENGTH (result_type) = sizeof (long);
+ else
+ error ("Ranged type doesn't fit within known sizes.");
+
+ TYPE_LENGTH (result_type) = TYPE_LENGTH (TYPE_TARGET_TYPE (result_type));
+ TYPE_CODE (result_type) = TYPE_CODE_RANGE;
+ TYPE_NFIELDS (result_type) = 2;
+ TYPE_FIELDS (result_type) =
+ (struct field *) obstack_alloc (symbol_obstack,
+ 2 * sizeof (struct field));
+ bzero (TYPE_FIELDS (result_type), 2 * sizeof (struct field));
+ TYPE_FIELD_BITPOS (result_type, 0) = n2;
+ TYPE_FIELD_BITPOS (result_type, 1) = n3;
+
+ return result_type;
+}
+
+/* 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. */
+
+static long
+read_number (pp, end)
+ char **pp;
+ int end;
+{
+ register char *p = *pp;
+ register long n = 0;
+ register int c;
+ int sign = 1;
+
+ /* Handle an optional leading minus sign. */
+
+ if (*p == '-')
+ {
+ sign = -1;
+ p++;
+ }
+
+ /* Read the digits, as far as they go. */
+
+ while ((c = *p++) >= '0' && c <= '9')
+ {
+ n *= 10;
+ n += c - '0';
+ }
+ if (end)
+ {
+ if (c && c != end)
+ error ("Invalid symbol data: invalid character \\%03o at symbol pos %d.", c, symnum);
+ }
+ else
+ --p;
+
+ *pp = p;
+ return n * sign;
+}
+
+static void
+read_huge_number (pp, end, valu, bits)
+ char **pp;
+ int end;
+ long *valu;
+ 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;
+
+ /* Handle an optional leading minus sign. */
+
+ 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++;
+ }
+
+ upper_limit = LONG_MAX / radix;
+ while ((c = *p++) >= '0' && c <= '9')
+ {
+ if (n <= upper_limit)
+ {
+ n *= radix;
+ n += c - '0';
+ }
+ 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;
+ }
+ }
+ 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;
+ }
+
+ /* -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 (valu)
+ *valu = n * sign;
+ if (bits)
+ *bits = 0;
+ }
+}
+
+/* Read in an argument list. This is a list of types. It is terminated with
+ a ':', FYI. Return the list of types read in. */
+static struct type **
+read_args (pp, end)
+ char **pp;
+ int end;
+{
+ struct type *types[1024], **rval; /* allow for fns of 1023 parameters */
+ int n = 0;
+
+ while (**pp != end)
+ {
+ if (**pp != ',')
+ error ("Invalid argument list: no ',', at symtab pos %d", symnum);
+ *pp += 1;
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (**pp == '\\')
+ *pp = next_symbol_text ();
+
+ types[n++] = read_type (pp);
+ }
+ *pp += 1; /* 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 *));
+ bzero (rval + n, sizeof (struct type *));
+ }
+ else
+ {
+ rval = (struct type **) xmalloc (n * sizeof (struct type *));
+ }
+ bcopy (types, rval, n * sizeof (struct type *));
+ return rval;
+}
+
+/* This function is really horrible, but to avoid it, there would need
+ to be more filling in of forward references. THIS SHOULD BE MOVED OUT
+ OF COFFREAD.C AND DBXREAD.C TO SOME PLACE WHERE IT CAN BE SHARED */
+int
+fill_in_vptr_fieldno (type)
+ struct type *type;
+{
+ if (TYPE_VPTR_FIELDNO (type) < 0)
+ TYPE_VPTR_FIELDNO (type) =
+ fill_in_vptr_fieldno (TYPE_BASECLASS (type, 1));
+ return TYPE_VPTR_FIELDNO (type);
+}
+
+/* Copy a pending list, used to record the contents of a common
+ block for later fixup. BUG FIX by rde@topexpress.co.uk */
+static struct pending *
+copy_pending (beg, begi, end)
+ struct pending *beg, *end;
+ int begi;
+{
+ struct pending *new = 0;
+ struct pending *next;
+
+ /* rde note: `begi' is an offset in block `end', NOT `beg' */
+ for (next = beg; next != 0; next = next->next)
+ {
+ register int j;
+ for (j = next == end ? begi : 0; j < next->nsyms; j++)
+ add_symbol_to_list (next->symbol[j], &new);
+
+ if (next == end)
+ break;
+ }
+ return new;
+}
+
+/* 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, value)
+ struct symbol *sym;
+ int value;
+{
+ struct pending *next = (struct pending *) SYMBOL_NAMESPACE (sym);
+ for ( ; next; next = next->next)
+ {
+ register int j;
+ for (j = next->nsyms - 1; j >= 0; j--)
+ SYMBOL_VALUE (next->symbol[j]) += value;
+ }
+}
+
+void
+_initialize_dbxread ()
+{
+ symfile = 0;
+ header_files = (struct header_file *) 0;
+ this_object_header_files = (int *) 0;
+
+ undef_types_allocated = 20;
+ undef_types_length = 0;
+ undef_types = (struct type **) xmalloc (undef_types_allocated *
+ sizeof (struct type *));
+
+ add_com ("symbol-file", class_files, symbol_file_command,
+ "Load symbol table (in dbx format) from executable file FILE.");
+
+ add_com ("add-file", class_files, add_file_command,
+ "Load the symbols from FILE, assuming its code is at TEXT_START.") ;
+}
+
+#endif /* READ_DBX_FORMAT */
diff --git a/gnu/usr.bin/gdb/defs.h b/gnu/usr.bin/gdb/defs.h
new file mode 100644
index 0000000..de744fc
--- /dev/null
+++ b/gnu/usr.bin/gdb/defs.h
@@ -0,0 +1,122 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ *
+ * @(#)defs.h 6.3 (Berkeley) 5/8/91
+ */
+
+/* Basic definitions for GDB, the GNU debugger.
+ Copyright (C) 1986, 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. */
+
+#define CORE_ADDR unsigned int
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+extern char *savestring ();
+extern char *concat ();
+extern char *xmalloc (), *xrealloc ();
+extern int parse_escape ();
+extern char *reg_names[];
+
+/* Various possibilities for alloca. */
+#ifdef sparc
+#include <alloca.h>
+#else
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+extern char *alloca ();
+#endif
+#endif
+
+extern int quit_flag;
+
+extern int immediate_quit;
+
+#define QUIT { if (quit_flag) quit (); }
+
+/* Notes on classes: class_alias is for alias commands which are not
+ abbreviations of the original command. */
+
+enum command_class
+{
+ no_class = -1, class_run = 0, class_vars, class_stack,
+ class_files, class_support, class_info, class_breakpoint,
+ class_alias, class_obscure, class_user,
+};
+
+/* 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) ();
+ int arg;
+};
+
+extern void do_cleanups ();
+extern void discard_cleanups ();
+extern struct cleanup *make_cleanup ();
+extern struct cleanup *save_cleanups ();
+extern void restore_cleanups ();
+extern void free_current_contents ();
+extern void reinitialize_more_filter ();
+extern void fputs_filtered ();
+extern void fprintf_filtered ();
+extern void printf_filtered ();
+extern void print_spaces_filtered ();
+extern char *tilde_expand ();
+
+/* Structure for saved commands lines
+ (for breakpoints, defined commands, etc). */
+
+struct command_line
+{
+ struct command_line *next;
+ char *line;
+ int type; /* statement type */
+#define CL_END 0
+#define CL_NORMAL 1
+#define CL_WHILE 2
+#define CL_IF 3
+#define CL_EXITLOOP 4
+#define CL_NOP 5
+ struct command_line *body; /* body of loop for while, body of if */
+ struct command_line *elsebody; /* body of else part of if */
+};
+
+extern struct command_line *read_command_lines ();
+extern void do_command_lines();
+
+/* String containing the current directory (what getwd would return). */
+
+char *current_directory;
+
diff --git a/gnu/usr.bin/gdb/doc/ChangeLog b/gnu/usr.bin/gdb/doc/ChangeLog
new file mode 100644
index 0000000..fb86719
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/ChangeLog
@@ -0,0 +1,783 @@
+Tue Oct 19 14:21:18 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo (Sourc Path): index entries for $cwd, $pdir
+
+ * a4rc.sed: update to work with Andreas Vogel papersize params
+
+ * refcard.tex: use Andreas Vogel simplifications of papersize
+ params; remove useless version info; update copyright date.
+
+Tue Oct 19 10:46:22 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdb.texinfo (Symbols): Add class NAME to doc for ptype.
+
+Tue Oct 12 09:11:45 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdb.texinfo (Files): Say what address the load command loads it at.
+
+ * stabs.texinfo (Common Blocks): Minor cleanups.
+
+ * stabs.texinfo: Update ld stabs in elf relocation to reflect the fact
+ that Sun has backed away from the linker kludge and thus the relevant
+ issue is changes to the SunPRO tools, not the Solaris linker.
+
+ * stabs.texinfo (Traditional Integer Types): Clean up description
+ of octal bounds a little bit. Document extra leading zeroes.
+
+Thu Oct 7 16:15:37 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdb.texinfo (Signaling): Update for symbolic symbol names
+ and add a section explaining the difference between the GDB
+ signal command and the shell kill utility.
+
+Wed Oct 6 13:23:01 1993 Tom Lord (lord@rtl.cygnus.com)
+
+ * libgdb.texinfo: added `@' to braces that were unescaped.
+
+Mon Oct 4 10:42:18 1993 Tom Lord (lord@rtl.cygnus.com)
+
+ * libgdb.texinfo: new file. Spec for the gdb library.
+
+Sun Oct 3 15:26:56 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Include Files): Fix typo (start -> end).
+
+Thu Sep 30 18:24:56 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo, remote.texi: assorted small improvements, mostly
+ from Melissa at FSF's editing pass.
+
+Thu Sep 30 11:54:38 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdb.texinfo: Remove stuff about ar and 14 character filenames.
+ I believe this was fixed by the 13 Sep 89 change to print_frame_info.
+ Also, modern versions of ar like BSD 4.4 or SVR4 don't have this bug.
+
+Wed Sep 22 21:22:11 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * remote.texi (Bootstrapping): Discuss 386 call gates.
+
+Sat Sep 18 17:10:44 1993 Jim Kingdon (kingdon@poseidon.cygnus.com)
+
+ * stabs.texinfo (Based Variables): New node.
+
+Thu Sep 16 17:48:55 1993 Jim Kingdon (kingdon@cirdan.cygnus.com)
+
+ * stabs.texinfo (Negative Type Numbers): Re-write discussions of
+ names, sizes, and formats to suggest how not to lose.
+
+Sat Sep 11 09:35:11 1993 Jim Kingdon (kingdon@poseidon.cygnus.com)
+
+ * stabs.texinfo (Methods): Fix typo.
+
+Fri Sep 10 06:34:20 1993 David J. Mackenzie (djm@thepub.cygnus.com)
+
+ * gdb.texinfo: Fix a few typos.
+
+Wed Sep 8 09:11:52 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdb.texinfo: Clarify how well it works with Fortran.
+
+ * stabs.texinfo (Stabs In ELF, Statics, ELF Transformations):
+ More on relocating stabs in ELF files.
+
+Tue Sep 7 13:45:02 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Stabs In ELF): Talk about N_FUN value.
+
+Mon Sep 6 19:23:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Local Variable Parameters): Talk about nameless
+ parameters on VAX.
+
+Fri Sep 3 17:06:08 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo: @up/@down -> @raisesections/@lowersections
+
+Fri Sep 3 12:04:15 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Make info author notice match the TeX author notice.
+
+Tue Aug 31 13:21:06 1993 David J. Mackenzie (djm@thepub.cygnus.com)
+
+ * stabs.texinfo: Initial-caps all words in node names and
+ non-trivial words in section names.
+
+Mon Aug 30 11:13:16 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Many minor cleanups.
+
+ * stabs.texinfo: Remove @deffn except from Expanded Reference node.
+
+Sat Aug 28 12:08:09 1993 David J. MacKenzie (djm@edison.eng.umd.edu)
+
+ * stabs.texinfo: Remove full description of big example.
+ It's not really helpful; just use pieces of it where appropriate.
+ Add more Texinfo formatting directives (@samp, etc.).
+ Use @deffn to define stab types.
+ Eliminate some wordiness. Break up some nodes.
+ Add an (alphabetized) index of symbol types.
+ Use consistent capitalization style in node and section names.
+
+Thu Aug 26 06:36:31 1993 Fred Fish (fnf@deneb.cygnus.com)
+
+ * gdb.texinfo: Change typo "Two two" to "The two".
+
+Sun Aug 22 12:15:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (XCOFF-differences): Remove references to
+ non-existent types N_DECL and N_RPSYM.
+
+ * stabs.texinfo (String Field): Say that type attributes bug is
+ fixed in GDB 4.10, since it is.
+
+ * stabs.texinfo: Clean up djm cleanups, and more cleanups of my own.
+
+Sat Aug 21 04:32:28 1993 David MacKenzie (djm@cygnus.com)
+
+ * stabs.texinfo: Formatting cleanups.
+
+Fri Aug 20 20:49:53 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: When explaining the n_type of a stab, standardize
+ how we do it ('#' as a comment indicator, "36 is N_FUN" as text,
+ no tabs, use @r).
+ (Global Variables): Clean up.
+
+Tue Aug 17 15:57:27 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Stack Variables): Re-write.
+
+Mon Aug 16 21:20:08 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Stabs-in-elf): Talk about getting the start
+ addresses of a source file. Also revise formatting.
+ Change "object module" or "object file" to "source file".
+ Various: Miscellaneous cleanups.
+
+Thu Aug 12 15:11:51 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Point to mangling info in gcc's gpcompare.texi.
+
+Tue Aug 10 16:57:49 1993 Stan Shebs (shebs@rtl.cygnus.com)
+
+ * gdbint.texinfo: Removed many nonsensical machine-collected
+ host and target conditionals, described some of the remainder.
+
+Tue Aug 10 13:28:30 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdbint.texinfo (Getting Started): Use @itemize, not @table.
+
+ * gdbint.texinfo (Top): Add name to @top line, and re-write the
+ paragraph which follows.
+
+ * gdbint.texinfo (Host): Use @code not @samp for Makefile
+ variables. Looks better and avoids overful hbox.
+
+Fri Jul 30 18:26:21 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Procedures): Improve stuff on nested functions.
+
+Thu Jul 29 15:10:58 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * remote.texi: (MIPS Remote) clearer doc for set/show timeout,
+ retransmit-timeout
+
+Thu Jul 29 13:16:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdbint.texinfo: Update statement about `some ancient Unix
+ systems, like Ultrix 4.0' to Ultrix 4.2.
+
+Wed Jul 28 15:26:53 1993 Roland H. Pesch (pesch@el_bosque.cygnus.com)
+
+ * h8-cfg.texi, all-cfg.texi: new flag GDBSERVER
+
+ * Makefile.in: depend on remote.texi rather than gdbinv-s.texi
+
+ * remote.texi: (Server) New node on gdbserver. (Remote Serial,
+ ST2000 Remote, MIPS Remote): mention `host:port' syntax for TCP.
+
+ * remote.texi: new name for former gdbinv-s.texi
+
+ * gdb.texinfo: use remote.texi rather than gdbinv-s.texi
+
+Wed Jul 28 08:26:24 1993 Ian Lance Taylor (ian@cygnus.com)
+
+ * gdbinv-s.texi: Documented timeout and retransmit-timeout
+ variables for MIPS remote debugging protocol.
+
+Mon Jul 26 13:00:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Negative Type Numbers): FORTRAN LOGICAL fix.
+
+Tue Jul 20 16:30:41 1993 Jim Kingdon (kingdon@deneb.cygnus.com)
+
+ * Makefile.in (refcard.dvi): Use srcdir where necessary.
+
+Mon Jul 19 12:02:50 1993 Roland H. Pesch (pesch@cygnus.com)
+
+ * gdb.texinfo: repair conditional bugs in text markup
+
+Fri Jul 16 18:57:50 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo, all-cfg.texi, h8-cfg.texi: introduce MOD2 switch
+ to select Modula-2 material.
+
+Thu Jul 15 13:15:01 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Cleanups regarding statics.
+
+ * gdbinv-s.texi (Bootstrapping): Document exceptionHandler.
+ (Debug Session): Mention exceptionHandler. Add xref to Bootstrapping.
+
+Mon Jul 12 13:37:02 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: N_MAIN is sometimes used for C.
+
+Fri Jul 9 09:47:02 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
+
+ * gdbint.texinfo (Host, Target Conditionals): Remove TM_FILE_OVERRIDE.
+
+Tue Jul 6 12:41:28 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo (Target Conditionals): Remove NO_TYPEDEFS,
+ removed from the code by Kingdon.
+
+Tue Jul 6 12:24:34 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * gdb.texinfo (Break Commands): Remove stuff about flushing terminal
+ input when evaluating breakpoint conditions; the bug has been fixed.
+
+ * gdb.texinfo (Continuing and Stepping): Argument to "continue"
+ sets the ignore count to N-1, not to N.
+
+Thu Jul 1 14:57:42 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * refcard.tex (\hoffset): correct longstanding error to match
+ intended offset; avoids cutting off edge on some printers
+
+Wed Jun 30 18:23:06 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Parameters): Say that order of stabs is significant.
+
+Fri Jun 25 21:34:52 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Common Blocks): Say what Sun FORTRAN does.
+
+Fri Jun 25 16:15:10 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * Makefile.in: (REFEDITS) new var to control whether PS or CM
+ fonts and whether US or A4 paper for GDB refcard; (refcard.dvi)
+ collect sed edits if any, apply to refcard before formatting;
+ (refcard.ps) stop implying PS fonts if PS output requested;
+ (lrefcard.ps) delete extra target for variant PS fonts
+
+ * refcard.tex: parametrize papersize dependent info, collect
+ in easily replaced spot
+
+ * a4rc.sed: new file, edits to refcard for A4 paper
+
+Fri Jun 25 14:21:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Negative Type Numbers): Type -16 is 4 bytes.
+
+Wed Jun 23 15:02:50 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Negative Type Numbers): Minor character cleanups.
+
+Tue Jun 22 16:31:52 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Express disapproval of 'D' symbol descriptor
+ politely rather than rudely.
+
+Fri Jun 18 19:42:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Document common blocks.
+
+Fri Jun 18 12:12:57 1993 Fred Fish (fnf@cygnus.com)
+
+ * stabs.texinfo: Add some basic info about stabs-in-elf.
+
+Fri Jun 18 13:57:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Top): Minor cleanup.
+
+Mon Jun 14 16:16:51 1993 david d `zoo' zuhn (zoo at rtl.cygnus.com)
+
+ * Makefile.in (install-info): remove parentdir support
+
+Tue Jun 15 18:11:39 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo (Copying): delete this node and references to it;
+ RMS says this manual need not carry GPL. (passim): Improvements
+ from last round at FSF, largely due to Ian Taylor review, and
+ minor formatting improvements.
+
+ * gdbinv-s.texi (passim): Improvements from last round at FSF,
+ largely due to Ian Taylor review. (Debug Session): minor edits to
+ new text.
+
+Sun Jun 13 12:52:39 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * Makefile.in (realclean): Remove info and dvi files too.
+
+Sat Jun 12 16:09:22 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * {all,h8}-config.texi: Rename to *-cfg.texi for 14 char filenames.
+ * Makefile.in: Change accordingly. gdb-config.texi -> gdb-cfg.texi.
+ * gdb.texinfo: Change accordingly.
+
+ * stabs.texinfo: Clean up N_{L,R}BRAC. Discuss what addresses of
+ N_{L,R}BRAC,N_SLINE are relative to.
+
+Fri Jun 11 15:15:55 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * Makefile.in (GDBvn.texi): Update atomically.
+
+Wed Jun 9 10:58:16 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * gdbinv-s.texi (Debug Session): Document exceptionHook.
+
+Tue Jun 8 13:42:04 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * gdb.texinfo (Print Settings): Move all stuff relating to symbolic
+ addresses together. Also motivate the set print symbol-filename
+ command and suggest other solutions.
+
+Tue Jun 1 22:46:43 1993 Fred Fish (fnf@cygnus.com)
+
+ * gdb.texinfo (set print elements): Note that the number of
+ elements is set to unlimited by "set print elements 0".
+
+Mon May 31 08:06:55 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo (Builtin Type Descriptors): Try to clarify what
+ NF_LDOUBLE means.
+ (Stab Types): Include Solaris stab types.
+ (Procedures): Document Solaris extensions.
+
+Thu May 27 06:20:42 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
+
+ * gdb.texinfo: Add `set print symbol-filename' doc.
+
+Wed May 26 00:26:42 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Arrays): Talk about type definition vs. type
+ information.
+
+ * stabs.texinfo (Builtin Type Descriptors): Talk about omitting
+ the trailing semicolon.
+
+Tue May 25 14:49:42 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Line Numbers, Source Files): Re-write these two nodes
+ and merge in other parts of the document addressing these subjects.
+ gdbint.texinfo (XCOFF): Remove info which is now in stabs.texinfo.
+
+ * stabs.texinfo (Subranges, Arrays): Try to explain about the semicolon
+ at the end of a range type.
+
+ * stabs.texinfo (Subranges): "A offset" and "T offset" are not
+ AIX extensions.
+
+Mon May 24 09:00:33 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Stabs Format): Misc fixes.
+
+Sat May 22 10:40:56 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Constants): Allow an `e' constant to be non-enum.
+ (Traditional builtin types): Document convex convention for long long.
+ (Negative builtin types): Discuss type names, and misc fixes.
+
+Fri May 21 11:20:31 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Builtin Type Descriptors): Document the floating
+ point types used with @samp{R} type descriptor.
+ (Symbol Descriptors): Describe how to handle conflict between
+ different meanings of @samp{P} symbol descriptor.
+
+Thu May 20 13:35:10 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo: Remove node Quick Reference and put its children
+ directly under the main menu.
+
+ * stabs.texinfo: Many more changes to bring it into line with
+ AIX documentation and reality. I think it now has all the
+ information from the AIX documentation, except that I burned
+ out when I got to variant records (Pascal and Modula-2) and
+ all the COBOL types. Oh well, we can add them later when we're
+ worrying more about those languages.
+
+ * stabs.texinfo (Automatic variables): Talk about what it means
+ to omit the symbol descriptor.
+
+Tue May 18 17:59:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * stabs.texinfo (Parameters): Add "(sometimes)" when describing
+ gcc2 behavior with promoted args.
+
+Fri May 14 21:35:29 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo: include readline appendices in info version of manual
+
+Fri May 7 11:56:18 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdbinv-s.texi (Remote Serial): describe new ^C behavior in
+ target remote.
+
+ * gdb.texinfo (Machine Code): more index entries for disassemble
+
+Fri May 7 10:12:30 1993 Fred Fish (fnf@cygnus.com)
+
+ * Clarify the intended use of the gdb-testers and gdb-patches
+ mailing lists, and shrink gzip comment.
+
+Thu May 6 16:39:50 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo (Shell Commands): do not mention SHELL env var in
+ DOSHOST configuration of manual.
+
+ * gdb.texinfo (MIPS Stack): new node.
+
+ * all-config.texi (MIPS) new switch.
+
+ * gdbinv-s.texi (Nindy Options) Remove two instances of future
+ tense; (MIPS Remote) new node.
+
+ * gdb.texinfo (passim) rephrases to work around makeinfo @value
+ bug; (Environment) less passive, other small cleanups in text about
+ .cshrc/.bashrc; (Invoking GDB) new MIPS Remote menu entry;
+ (Remote) new MIPS Remote menu entry.
+
+Thu Apr 29 09:36:25 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo: Many changes to include information from the
+ AIX documentation.
+
+ * gdb.texinfo (Environment): Mention pitfall with .cshrc.
+
+Tue Apr 27 14:02:57 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * gdbint.texinfo (new node Debugging GDB, elsewhere):
+ Move a bunch of information from ../README.
+ (Getting Started): New node.
+
+Fri Apr 23 17:21:13 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdbinv-s.texi, gdb.texinfo: include Hitachi SH target
+
+ * gdb.texinfo: advance manual revision dates to present
+
+ * gdbinv-s.texi, gdb.texinfo, all-config.texi, h8-config.texi:
+ stop using silly Roman numerals in @set variable names
+
+Fri Apr 23 07:30:01 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo (Parameters): Keep trying to get this right.
+
+Wed Apr 21 15:18:47 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo (Parameters): More on "local parameters".
+
+Mon Apr 19 08:00:51 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo (Parameters): Re-do "local parameters" section.
+
+Sun Apr 18 09:47:45 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo (Symbol descriptors): Re-do using @table and @xref.
+ (Parameters): Rewrite.
+ (xcoff-differences, Sun-differences): Minor changes.
+
+Thu Apr 15 02:35:24 1993 John Gilmore (gnu@cacophony.cygnus.com)
+
+ * stabs.texinfo: Minor cleanup.
+
+Wed Apr 14 17:31:00 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * gdbint.texinfo: Minor xcoff stuff.
+
+Wed Apr 7 14:11:07 1993 Fred Fish (fnf@cygnus.com)
+
+ * gdbint.texinfo: Update for new config directory structure.
+ Add info about internal type data structures.
+
+Mon Apr 5 09:06:30 1993 Ian Lance Taylor (ian@cygnus.com)
+
+ * Makefile.in (SFILES_INCLUDED): gdb-config.texi is no longer in
+ $(srcdir).
+ (gdb-config.texi): Depend on file in $(srcdir).
+
+Fri Apr 2 16:55:13 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo: Fixes about N_SO.
+
+Fri Mar 26 18:00:35 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo: include list of nonstandard init file names
+
+ * *-config.texi: new switch GENERIC for text that applies *only*
+ to (usual) multiple-target version of manual
+
+ * gdb.texinfo, gdbinv-s.texi: Update conditional markup to correct
+ h8 config
+
+ * gdb.texinfo: depend on latest fixed makeinfo, use conditionals
+ in menus (rather than conditionally selected multiple alternative
+ menus).
+
+ * Makefile.in: define and use DOC_CONFIG var to select
+ configuration for GDB user manual.
+
+ * gdb-config.texi: delete from repository, generate from Makefile.
+
+ * all-config.texi: normal `generic' configuration file, formerly
+ stored as gdb-config.texi
+
+Wed Mar 24 14:03:19 1993 david d `zoo' zuhn (zoo at poseidon.cygnus.com)
+
+ * Makefile.in: add dvi target to build all .dvi files
+
+Tue Mar 23 16:03:24 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo, gdvinv-s.texinfo: formatting improvements.
+
+Fri Mar 19 21:46:50 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Doc NO_MMALLOC and NO_MMALLOC_CHECK as
+ host conditionals.
+ * stabs.texinfo: More array fixes inspired by Jim's.
+
+Fri Mar 19 10:23:34 1993 Jim Kingdon (kingdon@cygnus.com)
+
+ * stabs.texinfo: Fixes re arrays and continuations.
+
+ * gdbint.texinfo: Add XCOFF node.
+
+Mon Mar 8 15:52:18 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdb.texinfo: Add `set print max-symbolic-offset' doc.
+
+Sun Feb 21 17:09:38 1993 Per Bothner (bothner@rtl.cygnus.com)
+
+ * stabs.texinfo: Fix for array types to mention lower bounds.
+
+Thu Feb 18 01:19:49 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Update PTRACE_ARG3_TYPE doc, pull PT_*.
+
+Wed Feb 17 08:15:24 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Remove SET_STACK_LIMIT_HUGE from target defines.
+
+Thu Feb 11 10:38:40 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Fix thinko (NM_FILE => NAT_FILE). Found
+ by Michael Ben-Gershon <mybg@CS.HUJI.AC.IL>.
+
+Wed Feb 10 23:59:19 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Eliminate IBM6000_HOST, document IBM6000_TARGET.
+
+Tue Feb 9 18:26:21 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo, gdbinv-s.texi: misc updates
+
+Sat Feb 6 10:25:47 1993 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Brief documentation for longjmp support,
+ from an email msg by Stu.
+
+Fri Feb 5 14:10:15 1993 John Gilmore (gnu@cygnus.com)
+
+ * stabs.texinfo: Fix description of floating point "range"
+ types (which really define basic types). Reported by Jim Meehan,
+ <meehan@src.dec.com>.
+
+ * gdbint.texinfo: Remove COFF_NO_LONG_FILE_NAMES define, now gone.
+
+Thu Feb 4 13:56:46 1993 Ian Lance Taylor (ian@cygnus.com)
+
+ * gdbint.texinfo: Slightly expand section on supporting a new
+ object file format.
+
+Thu Feb 4 01:49:04 1993 John Gilmore (gnu@cygnus.com)
+
+ * Makefile.in (refcard.ps, lrefcard.ps): Remove psref.tex
+ intermediate file.
+
+Tue Feb 2 12:18:06 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo, gdbinv-s.texi: miscellaneous stylistic cleanups
+
+Mon Feb 1 15:35:47 1993 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdbinv-s.texi: z8000 simulator target name is just "sim"
+
+ * gdbinv-s.texi: Mention that Z8000 simulator can simulate Z8001
+ as well as Z8002.
+
+Sat Nov 28 06:51:35 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Add sections on clean design and on how to send
+ in changes.
+
+Mon Nov 9 23:57:02 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Add how to declare the result of make_cleanup.
+
+Mon Oct 26 11:09:47 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdb.texinfo: Fix typo, reported by Karl Berry.
+
+Fri Oct 23 00:41:21 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdb.texinfo: Add opcodes dir to GDB distribution description.
+
+Sat Oct 10 18:04:58 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com)
+
+ * gdbint.texinfo: fixed a stray email address (needs @@),
+ added @table @code to node "Native Conditionals"
+
+Tue Sep 22 00:34:15 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Describe coding style of GDB.
+
+Mon Sep 21 19:32:16 1992 John Gilmore (gnu@cygnus.com)
+
+ * stabs.texinfo: Minor wording changes.
+
+Tue Sep 15 02:57:09 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Improve release doc slightly.
+
+Fri Sep 11 01:34:25 1992 John Gilmore (gnu@sphagnum.cygnus.com)
+
+ * gdbint.texinfo: Improve doc of GDB config macros.
+
+Wed Sep 9 16:52:06 1992 John Gilmore (gnu@cygnus.com)
+
+ * stabs.texinfo: Remove Bothner's changes for C++ nested types.
+ These will be reinserted when examined.
+
+Mon Aug 24 01:17:55 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Make a start at documenting all the #if macros
+ in GDB. At least list them all, and start separating them into
+ host-specific and target-specific.
+
+Tue Aug 18 15:59:13 1992 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdbinv-s.m4.in: refrain from using @cartouche for just a few
+ examples (not consistent w others).
+ gdb.texinfo: issue disclaimer paragraph on cmdline options only
+ for generic vn of doc
+
+Tue Aug 18 14:53:27 1992 Ian Lance Taylor (ian@cygnus.com)
+
+ * Makefile.in: always create installation directories.
+
+Tue Aug 18 14:11:50 1992 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo: in h8 config, do not describe searching commands.
+
+Mon Aug 17 18:07:59 1992 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo, none.m4, h8.m4, gdbinv-s.m4.in: improve H8/300
+ conditionals; introduce a few generic switches that may be
+ useful for other cross-dev or dos-hosted configs.
+
+ * gdb.texinfo: fix typo in "info reg" description
+
+Sun Aug 16 01:16:18 1992 John Gilmore (gnu@cygnus.com)
+
+ * stabs.texinfo: Minor updates from running TeX over it.
+ * Makefile.in (stabs.dvi, stabs.ps): Add.
+
+Sat Aug 15 20:52:24 1992 Per Bothner (bothner@rtl.cygnus.com)
+
+ * stabs.texinfo: Stabs documentation, written by Julia Menapace.
+ First pass at converting it to texinfo.
+
+Sat Aug 15 03:14:59 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdb.texinfo, refcard.tex: Document mult args on `info reg'.
+ * Makefile.in (refcard.ps, lrefcard.ps): Add missing $(srdir).
+
+Fri Aug 14 21:08:47 1992 John Gilmore (gnu@cygnus.com)
+
+ * gdbint.texinfo: Add section on partial symbol tables.
+
+Sat Jun 20 16:31:10 1992 John Gilmore (gnu at cygnus.com)
+
+ * gdb.texinfo: document `set remotedebug' and `set
+ rstack_high_address'.
+
+Thu May 14 17:09:48 1992 Roland H. Pesch (pesch@fowanton.cygnus.com)
+
+ * gdb.texinfo: slight expansion of new text on reading info files
+ * gdbinv-s.m4.in: correct and expand info on cross-debugging
+ H8/300 from DOS.
+
+Tue May 12 12:22:47 1992 John Gilmore (gnu at cygnus.com)
+
+ * gdb.texinfo: `info user' => `show user'. Noticed by David Taylor.
+
+Mon May 11 19:06:27 1992 John Gilmore (gnu at cygnus.com)
+
+ * gdb.texinfo: Say how to read the `info' files.
+
+Tue May 5 12:11:38 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * Makefile.in: gm4 -> m4.
+
+Fri Apr 10 17:50:43 1992 John Gilmore (gnu at rtl.cygnus.com)
+
+ * gdb.texinfo: Update for GDB-4.5. Move `Formatting
+ Documentation' ahead of `Installing GDB' to match README.
+ Update shared library doc, -readnow and -mapped, and directory
+ structure (add glob and mmalloc). Update configure doc.
+
+Tue Mar 24 23:28:38 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * Makefile.in: remove $(srcdir) from gdb.info rule.
+
+Sat Mar 7 18:44:50 1992 K. Richard Pixley (rich@rtl.cygnus.com)
+
+ * Makefile.in: commented out gdb-all.texinfo rule. This is
+ temporary.
+
+Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com)
+
+ * Makefile.in, configure.in: removed traces of namesubdir,
+ -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced
+ copyrights to '92, changed some from Cygnus to FSF.
+
+Fri Dec 13 09:47:31 1991 John Gilmore (gnu at cygnus.com)
+
+ * gdb.texinfo: Improve how we ask for bug reports.
+
+Tue Dec 10 04:07:21 1991 K. Richard Pixley (rich at rtl.cygnus.com)
+
+ * Makefile.in: infodir belongs in datadir.
+
+Fri Dec 6 23:57:34 1991 K. Richard Pixley (rich at rtl.cygnus.com)
+
+ * Makefile.in: remove spaces following hyphens, bsd make can't
+ cope. install using INSTALL_DATA. added clean-info. added
+ standards.text support.
+
+Thu Dec 5 22:46:12 1991 K. Richard Pixley (rich at rtl.cygnus.com)
+
+ * Makefile.in: idestdir and ddestdir go away. Added copyrights
+ and shift gpl to v2. Added ChangeLog if it didn't exist. docdir
+ and mandir now keyed off datadir by default.
+
+
+Local Variables:
+mode: indented-text
+left-margin: 8
+fill-column: 74
+version-control: never
+End:
diff --git a/gnu/usr.bin/gdb/doc/Makefile b/gnu/usr.bin/gdb/doc/Makefile
new file mode 100644
index 0000000..8cde5d4
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/Makefile
@@ -0,0 +1,340 @@
+# This file was generated automatically by configure. Do not edit.
+VPATH = .
+links =
+host_alias = i386-unknown-freebsd
+host_cpu = i386
+host_vendor = unknown
+host_os = freebsd
+host_canonical = i386-unknown-freebsd
+target_alias = i386-unknown-freebsd
+target_cpu = i386
+target_vendor = unknown
+target_os = freebsd
+target_canonical = i386-unknown-freebsd
+##Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+# Makefile for GDB documentation.
+# 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.
+
+srcdir = .
+
+prefix = /usr/gnu
+
+infodir = $(prefix)/info
+
+SHELL = /bin/sh
+
+INSTALL = install -c
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_DATA = $(INSTALL)
+
+# main GDB source directory
+gdbdir = $(srcdir)/..
+
+# where to find texinfo; GDB dist should include a recent one
+TEXIDIR=${gdbdir}/../texinfo
+
+# where to find makeinfo, preferably one designed for texinfo-2
+MAKEINFO=makeinfo
+
+# where to find texi2roff, ditto
+TEXI2ROFF=texi2roff
+
+# Where is the source dir for the READLINE library doc?
+# Traditionally readline is in .. or .
+READLINE_DIR = ${gdbdir}/../readline/doc
+
+SET_TEXINPUTS = TEXINPUTS=${TEXIDIR}:.:$(srcdir):$(READLINE_DIR):$$TEXINPUTS
+
+# There may be alternate predefined collections of switches to configure
+# the GDB manual. Normally this is not done in synch with the software
+# config system, since this choice tends to be independent; most people
+# want a doc config of `all' for a generic manual, regardless of sw config.
+DOC_CONFIG = all
+
+# This list of sed edits will edit the GDB reference card
+# for what fonts and what papersize to use.
+# By default (NO edits applied), the refcard uses:
+# - Computer Modern (CM) fonts
+# - US letter paper (8.5x11in)
+# List some of the following files for alternative fonts and paper:
+# a4rc.sed use A4 paper (297 x 210 mm)
+# psrc.sed use PostScript fonts (Karl Berry short TeX names)
+# lpsrc.sed use PostScript fonts (full PostScript names in TeX)
+# e.g. for A4, Postscript: REFEDITS = a4rc.sed psrc.sed
+# for A4, CM fonts: REFEDITS = a4rc.sed
+# for US, PS fonts: REFEDITS = psrc.sed
+# for default:
+REFEDITS =
+
+# Don Knuth's TeX formatter
+TEX = tex
+
+# auxiliary program for sorting Texinfo indices
+TEXINDEX = texindex
+
+# Main GDB manual's source files
+SFILES_INCLUDED = gdb-cfg.texi $(srcdir)/remote.texi
+
+SFILES_LOCAL = $(srcdir)/gdb.texinfo GDBvn.texi $(SFILES_INCLUDED)
+
+SFILES_DOC = $(SFILES_LOCAL) \
+ $(READLINE_DIR)/rluser.texinfo $(READLINE_DIR)/inc-hist.texi
+
+#### Host, target, and site specific Makefile fragments come in here.
+###
+
+all install:
+
+info: gdb.info gdbint.info stabs.info
+dvi: gdb.dvi refcard.dvi gdbint.dvi
+all-doc: gdb.info gdb.dvi refcard.dvi gdb-internals gdbint.dvi
+
+install-info: info
+ for i in *.info* ; do \
+ $(INSTALL_DATA) $$i $(infodir)/$$i ; \
+ done
+
+STAGESTUFF = *.info* gdb-all.texi GDBvn.texi
+
+# Copy the object files from a particular stage into a subdirectory.
+stage1: force
+ -mkdir stage1
+ -mv $(STAGESTUFF) stage1
+
+stage2: force
+ -mkdir stage2
+ -mv $(STAGESTUFF) stage2
+
+stage3: force
+ -mkdir stage3
+ -mv $(STAGESTUFF) stage3
+
+against=stage2
+
+comparison: force
+ for i in $(STAGESTUFF) ; do cmp $$i $(against)/$$i ; done
+
+de-stage1: force
+ -(cd stage1 ; mv -f * ..)
+ -rmdir stage1
+
+de-stage2: force
+ -(cd stage2 ; mv -f * ..)
+ -rmdir stage2
+
+de-stage3: force
+ -(cd stage3 ; mv -f * ..)
+ -rmdir stage3
+
+clean-info:
+ rm -f gdb.info* gdbint.info* stabs.info*
+
+clean-dvi:
+ rm -f gdb.dvi refcard.dvi gdbint.dvi stabs.dvi sedref.dvi
+
+mostlyclean: clean-info clean-dvi
+ rm -f gdb.?? gdb.??? gdb.mm gdb.ms gdb.me
+ rm -f links2roff
+ rm -f refcard.ps lrefcard.ps refcard.log sedref.* *~
+ rm -f gdbint.?? gdbint.??? stabs.?? stabs.???
+
+clean: mostlyclean
+ rm -f GDBvn.texi rluser.texinfo inc-hist.texi
+
+distclean: clean
+ rm -f Makefile config.status
+
+realclean: distclean clean-dvi clean-info
+
+# GDB QUICK REFERENCE (dvi output)
+refcard.dvi : refcard.tex $(REFEDITS)
+ if [ -z "$(REFEDITS)" ]; then \
+ cp $(srcdir)/refcard.tex sedref.tex ; \
+ else \
+ echo > tmp.sed ; \
+ for f in "$(REFEDITS)" ; do \
+ cat $(srcdir)/$$f >>tmp.sed ; done ; \
+ sed -f tmp.sed $(srcdir)/refcard.tex >sedref.tex ; \
+ fi
+ $(SET_TEXINPUTS) $(TEX) sedref.tex
+ mv sedref.dvi refcard.dvi
+ rm -f sedref.log sedref.tex tmp.sed
+
+refcard.ps : refcard.dvi
+ dvips -t landscape refcard.dvi -o
+
+# File to record current GDB version number (copied from main dir Makefile.in)
+GDBvn.texi : ${gdbdir}/Makefile.in
+ echo "@set GDBVN `sed <$(srcdir)/../Makefile.in -n 's/VERSION = //p'`" > ./GDBvn.new
+ mv GDBvn.new GDBvn.texi
+
+# Updated atomically
+.PRECIOUS: GDBvn.texi
+
+# Choose configuration for GDB manual (normally `all'; normally not tied into
+# `configure' script because most users prefer generic version of manual,
+# not one for their binary config---which may not be specifically
+# defined anyways).
+gdb-cfg.texi: ${srcdir}/${DOC_CONFIG}-cfg.texi
+ ln -s ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \
+ ln ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \
+ cp ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi
+
+# GDB MANUAL: texinfo source, using @set/@clear/@value/@ifset/@ifclear
+# If your texinfo or makeinfo don't support these, get a new texinfo release
+#
+# The nonsense with GDBvn.texi gets this to run with both Sun and GNU make.
+# Note that we can *generate* GDBvn.texi, but since we distribute one in the
+# source directory for the benefit of people who *don't* use this makefile,
+# VPATH will often tell make not to bother building it, because the one
+# in the srcdir is up to date. (if not, then make should build one here).
+
+# GDB MANUAL: TeX dvi file
+gdb.dvi: ${SFILES_DOC}
+ if [ ! -f ./GDBvn.texi ]; then \
+ ln -s $(srcdir)/GDBvn.texi . || \
+ ln $(srcdir)/GDBvn.texi . || \
+ cp $(srcdir)/GDBvn.texi . ; else true; fi
+ $(SET_TEXINPUTS) $(TEX) gdb.texinfo
+ $(SET_TEXINPUTS) $(TEX) gdb.texinfo
+ $(TEXINDEX) gdb.??
+ $(SET_TEXINPUTS) $(TEX) gdb.texinfo
+ rm -f gdb.?? gdb.log gdb.aux gdb.toc gdb.??s
+
+# GDB MANUAL: info file
+# We're using texinfo2, and older makeinfo's may not be able to
+# cope with all the markup.
+gdb.info: ${SFILES_DOC}
+ $(MAKEINFO) -I ${READLINE_DIR} -I $(srcdir) -o ./gdb.info gdb.texinfo
+
+# GDB MANUAL: roff translations
+# Try to use a recent texi2roff. v2 was put on prep in jan91.
+# If you want an index, see texi2roff doc for postprocessing
+# and add -i to texi2roff invocations below.
+# Workarounds for texi2roff-2 (probably fixed in later texi2roff's, delete
+# corresponding -e lines when later texi2roff's are current)
+# + @ifinfo's deleted explicitly due to texi2roff-2 bug w nested constructs.
+# + @c's deleted explicitly because texi2roff sees texinfo commands in them
+# + @ (that's at-BLANK) not recognized by texi2roff, turned into blank
+# + @alphaenumerate is ridiculously new, turned into @enumerate
+
+# texi2roff doesn't have a notion of include dirs, so we have to fake
+# it out for gdb manual's include files---but only if not configured
+# in main sourcedir.
+links2roff: $(SFILES_INCLUDED)
+ if [ ! -f gdb.texinfo ]; then \
+ ln -s $(SFILES_INCLUDED) . || \
+ ln $(SFILES_INCLUDED) . || \
+ cp $(SFILES_INCLUDED) . ; \
+ fi
+ touch links2roff
+
+# "Readline" appendices. Get them also due to lack of includes,
+# regardless of whether or not configuring in main sourcedir.
+# @ftable removed due to bug in texi2roff-2; if your texi2roff
+# is newer, try just ln or cp
+rluser.texinfo: ${READLINE_DIR}/rluser.texinfo
+ sed -e 's/^@ftable/@table/g' \
+ -e 's/^@end ftable/@end table/g' \
+ ${READLINE_DIR}/rluser.texinfo > ./rluser.texinfo
+
+inc-hist.texi: ${READLINE_DIR}/inc-hist.texi
+ ln -s ${READLINE_DIR}/inc-hist.texi . || \
+ ln ${READLINE_DIR}/inc-hist.texi . || \
+ cp ${READLINE_DIR}/inc-hist.texi .
+
+# gdb manual suitable for [gtn]roff -me
+gdb.me: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e '/^@ifinfo/,/^@end ifinfo/d' \
+ -e '/^@c /d' \
+ -e 's/{.*,,/{/' \
+ -e 's/@ / /g' \
+ -e 's/^@alphaenumerate/@enumerate/g' \
+ -e 's/^@end alphaenumerate/@end enumerate/g' \
+ $(srcdir)/gdb.texinfo | \
+ $(TEXI2ROFF) -me | \
+ sed -e 's/---/\\(em/g' \
+ >gdb.me
+
+# gdb manual suitable for [gtn]roff -ms
+gdb.ms: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e '/^@ifinfo/,/^@end ifinfo/d' \
+ -e '/^@c /d' \
+ -e 's/{.*,,/{/' \
+ -e 's/@ / /g' \
+ -e 's/^@alphaenumerate/@enumerate/g' \
+ -e 's/^@end alphaenumerate/@end enumerate/g' \
+ $(srcdir)/gdb.texinfo | \
+ $(TEXI2ROFF) -ms | \
+ sed -e 's/---/\\(em/g' \
+ >gdb.ms
+
+# gdb manual suitable for [tn]roff -mm
+# '@noindent's removed due to texi2roff-2 mm bug; if yours is newer,
+# try leaving them in
+gdb.mm: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e '/^@ifinfo/,/^@end ifinfo/d' \
+ -e '/^@c /d' \
+ -e 's/{.*,,/{/' \
+ -e '/@noindent/d' \
+ -e 's/@ / /g' \
+ -e 's/^@alphaenumerate/@enumerate/g' \
+ -e 's/^@end alphaenumerate/@end enumerate/g' \
+ $(srcdir)/gdb.texinfo | \
+ $(TEXI2ROFF) -mm | \
+ sed -e 's/---/\\(em/g' \
+ >gdb.mm
+
+# GDB INTERNALS MANUAL: TeX dvi file
+gdbint.dvi : gdbint.texinfo
+ $(SET_TEXINPUTS) $(TEX) gdbint.texinfo
+ $(TEXINDEX) gdbint.??
+ $(SET_TEXINPUTS) $(TEX) gdbint.texinfo
+ rm -f gdbint.?? gdbint.aux gdbint.cps gdbint.fns gdbint.kys \
+ gdbint.log gdbint.pgs gdbint.toc gdbint.tps gdbint.vrs
+
+# GDB INTERNALS MANUAL: info file
+gdb-internals: gdbint.info
+
+gdbint.info: gdbint.texinfo
+ $(MAKEINFO) -o gdbint.info $(srcdir)/gdbint.texinfo
+
+stabs.info: stabs.texinfo
+ $(MAKEINFO) -o stabs.info $(srcdir)/stabs.texinfo
+
+# STABS DOCUMENTATION: TeX dvi file
+stabs.dvi : stabs.texinfo
+ $(SET_TEXINPUTS) $(TEX) stabs.texinfo
+ $(TEXINDEX) stabs.??
+ $(SET_TEXINPUTS) $(TEX) stabs.texinfo
+ rm -f stabs.?? stabs.aux stabs.cps stabs.fns stabs.kys \
+ stabs.log stabs.pgs stabs.toc stabs.tps stabs.vrs
+
+stabs.ps: stabs.dvi
+ dvips -o stabs.ps stabs
+
+force:
+
+Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag)
+ $(SHELL) ./config.status
diff --git a/gnu/usr.bin/gdb/doc/Makefile.in b/gnu/usr.bin/gdb/doc/Makefile.in
new file mode 100644
index 0000000..d5ae290
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/Makefile.in
@@ -0,0 +1,327 @@
+##Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+# Makefile for GDB documentation.
+# 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.
+
+srcdir = .
+
+prefix = /usr/local
+
+infodir = $(prefix)/info
+
+SHELL = /bin/sh
+
+INSTALL = install -c
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_DATA = $(INSTALL)
+
+# main GDB source directory
+gdbdir = $(srcdir)/..
+
+# where to find texinfo; GDB dist should include a recent one
+TEXIDIR=${gdbdir}/../texinfo
+
+# where to find makeinfo, preferably one designed for texinfo-2
+MAKEINFO=makeinfo
+
+# where to find texi2roff, ditto
+TEXI2ROFF=texi2roff
+
+# Where is the source dir for the READLINE library doc?
+# Traditionally readline is in .. or .
+READLINE_DIR = ${gdbdir}/../readline/doc
+
+SET_TEXINPUTS = TEXINPUTS=${TEXIDIR}:.:$(srcdir):$(READLINE_DIR):$$TEXINPUTS
+
+# There may be alternate predefined collections of switches to configure
+# the GDB manual. Normally this is not done in synch with the software
+# config system, since this choice tends to be independent; most people
+# want a doc config of `all' for a generic manual, regardless of sw config.
+DOC_CONFIG = all
+
+# This list of sed edits will edit the GDB reference card
+# for what fonts and what papersize to use.
+# By default (NO edits applied), the refcard uses:
+# - Computer Modern (CM) fonts
+# - US letter paper (8.5x11in)
+# List some of the following files for alternative fonts and paper:
+# a4rc.sed use A4 paper (297 x 210 mm)
+# psrc.sed use PostScript fonts (Karl Berry short TeX names)
+# lpsrc.sed use PostScript fonts (full PostScript names in TeX)
+# e.g. for A4, Postscript: REFEDITS = a4rc.sed psrc.sed
+# for A4, CM fonts: REFEDITS = a4rc.sed
+# for US, PS fonts: REFEDITS = psrc.sed
+# for default:
+REFEDITS =
+
+# Don Knuth's TeX formatter
+TEX = tex
+
+# auxiliary program for sorting Texinfo indices
+TEXINDEX = texindex
+
+# Main GDB manual's source files
+SFILES_INCLUDED = gdb-cfg.texi $(srcdir)/remote.texi
+
+SFILES_LOCAL = $(srcdir)/gdb.texinfo GDBvn.texi $(SFILES_INCLUDED)
+
+SFILES_DOC = $(SFILES_LOCAL) \
+ $(READLINE_DIR)/rluser.texinfo $(READLINE_DIR)/inc-hist.texi
+
+#### Host, target, and site specific Makefile fragments come in here.
+###
+
+all install:
+
+info: gdb.info gdbint.info stabs.info
+dvi: gdb.dvi refcard.dvi gdbint.dvi
+all-doc: gdb.info gdb.dvi refcard.dvi gdb-internals gdbint.dvi
+
+install-info: info
+ for i in *.info* ; do \
+ $(INSTALL_DATA) $$i $(infodir)/$$i ; \
+ done
+
+STAGESTUFF = *.info* gdb-all.texi GDBvn.texi
+
+# Copy the object files from a particular stage into a subdirectory.
+stage1: force
+ -mkdir stage1
+ -mv $(STAGESTUFF) stage1
+
+stage2: force
+ -mkdir stage2
+ -mv $(STAGESTUFF) stage2
+
+stage3: force
+ -mkdir stage3
+ -mv $(STAGESTUFF) stage3
+
+against=stage2
+
+comparison: force
+ for i in $(STAGESTUFF) ; do cmp $$i $(against)/$$i ; done
+
+de-stage1: force
+ -(cd stage1 ; mv -f * ..)
+ -rmdir stage1
+
+de-stage2: force
+ -(cd stage2 ; mv -f * ..)
+ -rmdir stage2
+
+de-stage3: force
+ -(cd stage3 ; mv -f * ..)
+ -rmdir stage3
+
+clean-info:
+ rm -f gdb.info* gdbint.info* stabs.info*
+
+clean-dvi:
+ rm -f gdb.dvi refcard.dvi gdbint.dvi stabs.dvi sedref.dvi
+
+mostlyclean: clean-info clean-dvi
+ rm -f gdb.?? gdb.??? gdb.mm gdb.ms gdb.me
+ rm -f links2roff
+ rm -f refcard.ps lrefcard.ps refcard.log sedref.* *~
+ rm -f gdbint.?? gdbint.??? stabs.?? stabs.???
+
+clean: mostlyclean
+ rm -f GDBvn.texi rluser.texinfo inc-hist.texi
+
+distclean: clean
+ rm -f Makefile config.status
+
+realclean: distclean clean-dvi clean-info
+
+# GDB QUICK REFERENCE (dvi output)
+refcard.dvi : refcard.tex $(REFEDITS)
+ if [ -z "$(REFEDITS)" ]; then \
+ cp $(srcdir)/refcard.tex sedref.tex ; \
+ else \
+ echo > tmp.sed ; \
+ for f in "$(REFEDITS)" ; do \
+ cat $(srcdir)/$$f >>tmp.sed ; done ; \
+ sed -f tmp.sed $(srcdir)/refcard.tex >sedref.tex ; \
+ fi
+ $(SET_TEXINPUTS) $(TEX) sedref.tex
+ mv sedref.dvi refcard.dvi
+ rm -f sedref.log sedref.tex tmp.sed
+
+refcard.ps : refcard.dvi
+ dvips -t landscape refcard.dvi -o
+
+# File to record current GDB version number (copied from main dir Makefile.in)
+GDBvn.texi : ${gdbdir}/Makefile.in
+ echo "@set GDBVN `sed <$(srcdir)/../Makefile.in -n 's/VERSION = //p'`" > ./GDBvn.new
+ mv GDBvn.new GDBvn.texi
+
+# Updated atomically
+.PRECIOUS: GDBvn.texi
+
+# Choose configuration for GDB manual (normally `all'; normally not tied into
+# `configure' script because most users prefer generic version of manual,
+# not one for their binary config---which may not be specifically
+# defined anyways).
+gdb-cfg.texi: ${srcdir}/${DOC_CONFIG}-cfg.texi
+ ln -s ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \
+ ln ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \
+ cp ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi
+
+# GDB MANUAL: texinfo source, using @set/@clear/@value/@ifset/@ifclear
+# If your texinfo or makeinfo don't support these, get a new texinfo release
+#
+# The nonsense with GDBvn.texi gets this to run with both Sun and GNU make.
+# Note that we can *generate* GDBvn.texi, but since we distribute one in the
+# source directory for the benefit of people who *don't* use this makefile,
+# VPATH will often tell make not to bother building it, because the one
+# in the srcdir is up to date. (if not, then make should build one here).
+
+# GDB MANUAL: TeX dvi file
+gdb.dvi: ${SFILES_DOC}
+ if [ ! -f ./GDBvn.texi ]; then \
+ ln -s $(srcdir)/GDBvn.texi . || \
+ ln $(srcdir)/GDBvn.texi . || \
+ cp $(srcdir)/GDBvn.texi . ; else true; fi
+ $(SET_TEXINPUTS) $(TEX) gdb.texinfo
+ $(SET_TEXINPUTS) $(TEX) gdb.texinfo
+ $(TEXINDEX) gdb.??
+ $(SET_TEXINPUTS) $(TEX) gdb.texinfo
+ rm -f gdb.?? gdb.log gdb.aux gdb.toc gdb.??s
+
+# GDB MANUAL: info file
+# We're using texinfo2, and older makeinfo's may not be able to
+# cope with all the markup.
+gdb.info: ${SFILES_DOC}
+ $(MAKEINFO) -I ${READLINE_DIR} -I $(srcdir) -o ./gdb.info gdb.texinfo
+
+# GDB MANUAL: roff translations
+# Try to use a recent texi2roff. v2 was put on prep in jan91.
+# If you want an index, see texi2roff doc for postprocessing
+# and add -i to texi2roff invocations below.
+# Workarounds for texi2roff-2 (probably fixed in later texi2roff's, delete
+# corresponding -e lines when later texi2roff's are current)
+# + @ifinfo's deleted explicitly due to texi2roff-2 bug w nested constructs.
+# + @c's deleted explicitly because texi2roff sees texinfo commands in them
+# + @ (that's at-BLANK) not recognized by texi2roff, turned into blank
+# + @alphaenumerate is ridiculously new, turned into @enumerate
+
+# texi2roff doesn't have a notion of include dirs, so we have to fake
+# it out for gdb manual's include files---but only if not configured
+# in main sourcedir.
+links2roff: $(SFILES_INCLUDED)
+ if [ ! -f gdb.texinfo ]; then \
+ ln -s $(SFILES_INCLUDED) . || \
+ ln $(SFILES_INCLUDED) . || \
+ cp $(SFILES_INCLUDED) . ; \
+ fi
+ touch links2roff
+
+# "Readline" appendices. Get them also due to lack of includes,
+# regardless of whether or not configuring in main sourcedir.
+# @ftable removed due to bug in texi2roff-2; if your texi2roff
+# is newer, try just ln or cp
+rluser.texinfo: ${READLINE_DIR}/rluser.texinfo
+ sed -e 's/^@ftable/@table/g' \
+ -e 's/^@end ftable/@end table/g' \
+ ${READLINE_DIR}/rluser.texinfo > ./rluser.texinfo
+
+inc-hist.texi: ${READLINE_DIR}/inc-hist.texi
+ ln -s ${READLINE_DIR}/inc-hist.texi . || \
+ ln ${READLINE_DIR}/inc-hist.texi . || \
+ cp ${READLINE_DIR}/inc-hist.texi .
+
+# gdb manual suitable for [gtn]roff -me
+gdb.me: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e '/^@ifinfo/,/^@end ifinfo/d' \
+ -e '/^@c /d' \
+ -e 's/{.*,,/{/' \
+ -e 's/@ / /g' \
+ -e 's/^@alphaenumerate/@enumerate/g' \
+ -e 's/^@end alphaenumerate/@end enumerate/g' \
+ $(srcdir)/gdb.texinfo | \
+ $(TEXI2ROFF) -me | \
+ sed -e 's/---/\\(em/g' \
+ >gdb.me
+
+# gdb manual suitable for [gtn]roff -ms
+gdb.ms: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e '/^@ifinfo/,/^@end ifinfo/d' \
+ -e '/^@c /d' \
+ -e 's/{.*,,/{/' \
+ -e 's/@ / /g' \
+ -e 's/^@alphaenumerate/@enumerate/g' \
+ -e 's/^@end alphaenumerate/@end enumerate/g' \
+ $(srcdir)/gdb.texinfo | \
+ $(TEXI2ROFF) -ms | \
+ sed -e 's/---/\\(em/g' \
+ >gdb.ms
+
+# gdb manual suitable for [tn]roff -mm
+# '@noindent's removed due to texi2roff-2 mm bug; if yours is newer,
+# try leaving them in
+gdb.mm: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi
+ sed -e '/\\input texinfo/d' \
+ -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \
+ -e '/^@ifinfo/,/^@end ifinfo/d' \
+ -e '/^@c /d' \
+ -e 's/{.*,,/{/' \
+ -e '/@noindent/d' \
+ -e 's/@ / /g' \
+ -e 's/^@alphaenumerate/@enumerate/g' \
+ -e 's/^@end alphaenumerate/@end enumerate/g' \
+ $(srcdir)/gdb.texinfo | \
+ $(TEXI2ROFF) -mm | \
+ sed -e 's/---/\\(em/g' \
+ >gdb.mm
+
+# GDB INTERNALS MANUAL: TeX dvi file
+gdbint.dvi : gdbint.texinfo
+ $(SET_TEXINPUTS) $(TEX) gdbint.texinfo
+ $(TEXINDEX) gdbint.??
+ $(SET_TEXINPUTS) $(TEX) gdbint.texinfo
+ rm -f gdbint.?? gdbint.aux gdbint.cps gdbint.fns gdbint.kys \
+ gdbint.log gdbint.pgs gdbint.toc gdbint.tps gdbint.vrs
+
+# GDB INTERNALS MANUAL: info file
+gdb-internals: gdbint.info
+
+gdbint.info: gdbint.texinfo
+ $(MAKEINFO) -o gdbint.info $(srcdir)/gdbint.texinfo
+
+stabs.info: stabs.texinfo
+ $(MAKEINFO) -o stabs.info $(srcdir)/stabs.texinfo
+
+# STABS DOCUMENTATION: TeX dvi file
+stabs.dvi : stabs.texinfo
+ $(SET_TEXINPUTS) $(TEX) stabs.texinfo
+ $(TEXINDEX) stabs.??
+ $(SET_TEXINPUTS) $(TEX) stabs.texinfo
+ rm -f stabs.?? stabs.aux stabs.cps stabs.fns stabs.kys \
+ stabs.log stabs.pgs stabs.toc stabs.tps stabs.vrs
+
+stabs.ps: stabs.dvi
+ dvips -o stabs.ps stabs
+
+force:
+
+Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag)
+ $(SHELL) ./config.status
diff --git a/gnu/usr.bin/gdb/doc/a4rc.sed b/gnu/usr.bin/gdb/doc/a4rc.sed
new file mode 100644
index 0000000..2292290
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/a4rc.sed
@@ -0,0 +1,11 @@
+/--- Papersize params:/,/--- end papersize params/c\
+%------- Papersize params:\
+%% A4 paper (297x210mm)\
+%%\
+\\totalwidth=297mm % total width of paper\
+\\totalheight=210mm % total height of paper\
+\\hmargin=5mm % horizontal margin width\
+\\vmargin=10mm % vertical margin width\
+\\secskip=.6pc % space between refcard secs\
+\\lskip=1pt % extra skip between \\sec entries\
+%------- end papersize params
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/config.status b/gnu/usr.bin/gdb/doc/config.status
new file mode 100755
index 0000000..5d2c6dd
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/config.status
@@ -0,0 +1,5 @@
+#!/bin/sh
+# This file was generated automatically by configure. Do not edit.
+# This directory was configured as follows:
+../../configure --host=i386-unknown-freebsd --target=i386-unknown-freebsd -norecursion
+#
diff --git a/gnu/usr.bin/gdb/doc/configure.in b/gnu/usr.bin/gdb/doc/configure.in
new file mode 100644
index 0000000..1d2b47e
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/configure.in
@@ -0,0 +1,7 @@
+srcname="GDB doc"
+srctrigger=gdb.texinfo
+# per-host:
+# per-target:
+
+files=""
+links=""
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.info b/gnu/usr.bin/gdb/doc/gdb.info
new file mode 100644
index 0000000..c326469
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info
@@ -0,0 +1,213 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ 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.
+
+ 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.
+
+
+Indirect:
+gdb.info-1: 992
+gdb.info-2: 50863
+gdb.info-3: 98423
+gdb.info-4: 145674
+gdb.info-5: 194815
+gdb.info-6: 244253
+gdb.info-7: 290141
+gdb.info-8: 335234
+
+Tag Table:
+(Indirect)
+Node: Top992
+Node: Summary2561
+Node: Free Software3754
+Node: Contributors4492
+Node: New Features8199
+Node: Sample Session12215
+Node: Invocation19094
+Node: Invoking GDB19559
+Node: File Options21298
+Node: Mode Options24476
+Node: Quitting GDB26641
+Node: Shell Commands27359
+Node: Commands28106
+Node: Command Syntax28739
+Node: Completion30598
+Node: Help34666
+Node: Running38442
+Node: Compilation39426
+Node: Starting41224
+Node: Arguments44411
+Node: Environment45412
+Node: Working Directory48518
+Node: Input/Output49258
+Node: Attach50863
+Node: Kill Process53122
+Node: Process Information54097
+Node: Stopping55350
+Node: Breakpoints56423
+Node: Set Breaks58622
+Node: Set Watchpoints65221
+Node: Exception Handling66051
+Node: Delete Breaks68610
+Node: Disabling70238
+Node: Conditions72881
+Node: Break Commands77378
+Node: Breakpoint Menus80225
+Node: Error in Breakpoints81935
+Node: Continuing and Stepping82839
+Node: Signals89318
+Node: Stack92940
+Node: Frames94414
+Node: Backtrace96691
+Node: Selection98423
+Node: Frame Info100917
+Node: MIPS Stack102984
+Node: Source103857
+Node: List104806
+Node: Search108286
+Node: Source Path109085
+Node: Machine Code111763
+Node: Data114236
+Node: Expressions116111
+Node: Variables117793
+Node: Arrays120314
+Node: Output Formats122397
+Node: Memory124456
+Node: Auto Display128727
+Node: Print Settings132474
+Node: Value History140630
+Node: Convenience Vars143017
+Node: Registers145674
+Node: Floating Point Hardware150276
+Node: Languages150781
+Node: Setting151949
+Node: Manually152483
+Node: Automatically153663
+Node: Show154980
+Node: Checks155888
+Node: Type Checking157244
+Node: Range Checking159924
+Node: Support162265
+Node: C163185
+Node: C Operators164016
+Node: C Constants168071
+Node: Cplus expressions169974
+Node: C Defaults172597
+Node: C Checks173215
+Node: Debugging C173926
+Node: Debugging C plus plus174404
+Node: Modula-2176416
+Node: M2 Operators177308
+Node: Built-In Func/Proc180308
+Node: M2 Constants183051
+Node: M2 Defaults184640
+Node: Deviations185239
+Node: M2 Checks186330
+Node: M2 Scope187130
+Node: GDB/M2188142
+Node: Symbols189081
+Node: Altering194815
+Node: Assignment195797
+Node: Jumping197907
+Node: Signaling199914
+Node: Returning201034
+Node: Calling202226
+Node: Patching202700
+Node: GDB Files203782
+Node: Files204247
+Node: Symbol Errors214466
+Node: Targets218064
+Node: Active Targets218954
+Node: Target Commands220530
+Node: Remote223904
+Node: Remote Serial225315
+Node: Stub Contents227768
+Node: Bootstrapping229877
+Node: Debug Session233057
+Node: Protocol236218
+Node: Server239069
+Node: i960-Nindy Remote242748
+Node: Nindy Startup243568
+Node: Nindy Options244253
+Node: Nindy Reset245867
+Node: UDI29K Remote246251
+Node: EB29K Remote247172
+Node: Comms (EB29K)248006
+Node: gdb-EB29K251189
+Node: Remote Log252555
+Node: ST2000 Remote253030
+Node: VxWorks Remote254499
+Node: VxWorks Connection256224
+Node: VxWorks Download257150
+Node: VxWorks Attach258886
+Node: Hitachi Remote259281
+Node: MIPS Remote260790
+Node: Simulator262861
+Node: Controlling GDB264351
+Node: Prompt264962
+Node: Editing265571
+Node: History266338
+Node: Screen Size269024
+Node: Numbers270420
+Node: Messages/Warnings271538
+Node: Sequences274587
+Node: Define275147
+Node: Hooks277144
+Node: Command Files278547
+Node: Output280302
+Node: Emacs282714
+Node: GDB Bugs288669
+Node: Bug Criteria289387
+Node: Bug Reporting290141
+Node: Command Line Editing297342
+Node: Introduction and Notation297763
+Node: Readline Interaction298780
+Node: Readline Bare Essentials299914
+Node: Readline Movement Commands301417
+Node: Readline Killing Commands302303
+Node: Readline Arguments303941
+Node: Readline Init File304887
+Node: Readline Init Syntax305708
+Node: Commands For Moving309640
+Node: Commands For History310260
+Node: Commands For Text311330
+Node: Commands For Killing313046
+Node: Numeric Arguments314168
+Node: Commands For Completion314606
+Node: Miscellaneous Commands315325
+Node: Readline Vi Mode316077
+Node: Using History Interactively316784
+Node: History Interaction317141
+Node: Event Designators318189
+Node: Word Designators318828
+Node: Modifiers319724
+Node: Renamed Commands320469
+Node: Formatting Documentation322131
+Node: Installing GDB325465
+Node: Separate Objdir328945
+Node: Config Names331490
+Node: configure Options332918
+Node: Index335234
+
+End Tag Table
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-1 b/gnu/usr.bin/gdb/doc/gdb.info-1
new file mode 100644
index 0000000..a1d7120
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-1
@@ -0,0 +1,1304 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ 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.
+
+ 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.
+
+
+File: gdb.info, Node: Top, Next: Summary, Prev: (DIR), Up: (DIR)
+
+Debugging with GDB
+******************
+
+ This file describes GDB, the GNU symbolic debugger.
+
+ This is Edition 4.09, August 1993, for GDB Version 4.11.
+
+* Menu:
+
+* Summary:: Summary of GDB
+
+* New Features:: New features since GDB version 3.5
+
+* Sample Session:: A sample GDB session
+
+* Invocation:: Getting in and out of GDB
+* Commands:: GDB commands
+* Running:: Running programs under GDB
+* Stopping:: Stopping and continuing
+* Stack:: Examining the stack
+* Source:: Examining source files
+* Data:: Examining data
+
+* Languages:: Using GDB with different languages
+
+
+* Symbols:: Examining the symbol table
+* Altering:: Altering execution
+* GDB Files:: GDB files
+* Targets:: Specifying a debugging target
+* Controlling GDB:: Controlling GDB
+* Sequences:: Canned sequences of commands
+
+* Emacs:: Using GDB under GNU Emacs
+
+* GDB Bugs:: Reporting bugs in GDB
+* Command Line Editing:: Facilities of the readline library
+* Using History Interactively::
+
+* Renamed Commands::
+
+* Formatting Documentation:: How to format and print GDB documentation
+* Installing GDB:: Installing GDB
+
+* Index:: Index
+
+
+File: gdb.info, Node: Summary, Next: New Features, Prev: Top, Up: Top
+
+Summary of GDB
+**************
+
+ The purpose of a debugger such as GDB 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.
+
+ GDB can do four main kinds of things (plus other things in support of
+these) to help you catch bugs in the act:
+
+ * Start your program, specifying anything that might affect its
+ behavior.
+
+ * Make your program stop on specified conditions.
+
+ * Examine what has happened, when your program has stopped.
+
+ * Change things in your program, so you can experiment with
+ correcting the effects of one bug and go on to learn about another.
+
+ You can use GDB to debug programs written in C, C++, and Modula-2.
+G{No Value For "DBN"} can be used to debug programs written in Fortran,
+although it does not yet support entering expressions, printing values,
+etc. using Fortran syntax. It may be necessary to refer to some
+variables with a trailing underscore.
+
+* Menu:
+
+* Free Software:: Freely redistributable software
+* Contributors:: Contributors to GDB
+
+
+File: gdb.info, Node: Free Software, Next: Contributors, Up: Summary
+
+Free software
+=============
+
+ GDB is "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.
+
+
+File: gdb.info, Node: Contributors, Prev: Free Software, Up: Summary
+
+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
+`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.
+
+ *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!
+
+ 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.11, 4.10, 4.9), Stu Grossman and John Gilmore (releases
+4.8, 4.7, 4.6, 4.5, 4.4), John Gilmore (releases 4.3, 4.2, 4.1, 4.0, and
+3.9); Jim Kingdon (releases 3.5, 3.4, 3.3); and Randy Smith (releases
+3.2, 3.1, 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.
+
+ 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).
+
+ 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.
+Keith Packard contributed NS32K support. Doug Rabson contributed Acorn
+Risc Machine 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, the
+Modula-2 support, and contributed the Languages chapter of this manual.
+
+ Fred Fish wrote most of the support for Unix System Vr4. He also
+enhanced the command-completion support to cover C++ overloaded symbols.
+
+ Hitachi America, Ltd. sponsored the support for Hitachi
+microprocessors.
+
+
+File: gdb.info, Node: New Features, Next: Sample Session, Prev: Summary, Up: Top
+
+New Features since GDB Version 3.5
+**********************************
+
+*Targets*
+ Using the new command `target', you can select at runtime whether
+ you are debugging local files, local processes, standalone systems
+ over a serial port, realtime systems over a TCP/IP connection,
+ etc. The command `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.
+
+*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.
+
+*Wide Output*
+ Commands that issue wide output now insert newlines at places
+ designed to make the output more readable.
+
+*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.
+
+*Configuration and Ports*
+ Compile-time configuration (to select a particular architecture and
+ operating system) is much easier. The script `configure' now
+ allows you to configure GDB as either a native debugger or a
+ cross-debugger. *Note Installing GDB::, for details on how to
+ configure.
+
+*Interaction*
+ The user interface to the GDB control variables is simpler, and is
+ consolidated in two commands, `set' and `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.
+
+*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 `catch' and `info catch': GDB can
+ break when an exception is raised, before the stack is peeled back
+ to the exception handler's context.
+
+*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.
+
+*Command Rationalization*
+ Many GDB commands have been renamed to make them easier to remember
+ and use. In particular, the subcommands of `info' and
+ `show'/`set' are grouped to make the former refer to the state of
+ your program, and the latter refer to the state of GDB itself.
+ *Note Renamed Commands::, for details on what commands were
+ renamed.
+
+*Shared Libraries*
+ GDB 4 can debug programs and core files that use SunOS, SVR4, or
+ IBM RS/6000 shared libraries.
+
+*Reference Card*
+ GDB 4 has a reference card. *Note Formatting the Documentation:
+ Formatting Documentation, for instructions about how to print it.
+
+
+File: gdb.info, Node: Sample Session, Next: Invocation, Prev: New Features, Up: Top
+
+A Sample GDB Session
+********************
+
+ You can use this manual at your leisure to read all about GDB.
+However, a handful of commands are enough to get started using the
+debugger. This chapter illustrates those commands.
+
+ One of the preliminary versions of GNU `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 `m4'
+session, we define a macro `foo' which expands to `0000'; we then use
+the `m4' built-in `defn' to define `bar' as the same thing. However,
+when we change the open quote string to `<QUOTE>' and the close quote
+string to `<UNQUOTE>', the same procedure fails to define a new synonym
+`baz':
+
+ $ cd gnu/m4
+ $ ./m4
+ define(foo,0000)
+
+ foo
+ 0000
+ define(bar,defn(`foo'))
+
+ bar
+ 0000
+ changequote(<QUOTE>,<UNQUOTE>)
+
+ define(baz,defn(<QUOTE>foo<UNQUOTE>))
+ baz
+ C-d
+ m4: End of input: 0: fatal error: EOF in string
+
+Let us use GDB to try to see what is going on.
+
+ $ gdb m4
+ 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.11, Copyright 1993 Free Software Foundation, Inc...
+ (gdb)
+
+GDB 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 GDB to use a narrower display width than usual, so that examples
+will fit in this manual.
+
+ (gdb) set width 70
+
+We need to see how the `m4' built-in `changequote' works. Having
+looked at the source, we know the relevant subroutine is
+`m4_changequote', so we set a breakpoint there with the GDB `break'
+command.
+
+ (gdb) break m4_changequote
+ Breakpoint 1 at 0x62f4: file builtin.c, line 879.
+
+Using the `run' command, we start `m4' running under GDB control; as
+long as control does not reach the `m4_changequote' subroutine, the
+program runs as usual:
+
+ (gdb) run
+ Starting program: /work/Editorial/gdb/gnu/m4/m4
+ define(foo,0000)
+
+ foo
+ 0000
+
+To trigger the breakpoint, we call `changequote'. GDB suspends
+execution of `m4', displaying information about the context where it
+stops.
+
+ 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))
+
+Now we use the command `n' (`next') to advance execution to the next
+line of the current function.
+
+ (gdb) n
+ 882 set_quotes((argc >= 2) ? TOKEN_DATA_TEXT(argv[1])\
+ : nil,
+
+`set_quotes' looks like a promising subroutine. We can go into it by
+using the command `s' (`step') instead of `next'. `step' goes to the
+next line to be executed in *any* subroutine, so it steps into
+`set_quotes'.
+
+ (gdb) s
+ set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>")
+ at input.c:530
+ 530 if (lquote != def_lquote)
+
+The display that shows the subroutine where `m4' is now suspended (and
+its arguments) is called a stack frame display. It shows a summary of
+the stack. We can use the `backtrace' command (which can also be
+spelled `bt'), to see where we are in the stack as a whole: the
+`backtrace' command displays a stack frame for each active subroutine.
+
+ (gdb) 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
+
+We will step through a few more lines to see what happens. The first
+two times, we can use `s'; the next two times we use `n' to avoid
+falling into the `xstrdup' subroutine.
+
+ (gdb) s
+ 0x3b5c 532 if (rquote != def_rquote)
+ (gdb) s
+ 0x3b80 535 lquote = (lq == nil || *lq == '\0') ? \
+ def_lquote : xstrdup(lq);
+ (gdb) n
+ 536 rquote = (rq == nil || *rq == '\0') ? def_rquote\
+ : xstrdup(rq);
+ (gdb) n
+ 538 len_lquote = strlen(rquote);
+
+The last line displayed looks a little odd; we can examine the variables
+`lquote' and `rquote' to see if they are in fact the new left and right
+quotes we specified. We use the command `p' (`print') to see their
+values.
+
+ (gdb) p lquote
+ $1 = 0x35d40 "<QUOTE>"
+ (gdb) p rquote
+ $2 = 0x35d50 "<UNQUOTE>"
+
+`lquote' and `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 `l' (`list') command.
+
+ (gdb) 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
+
+Let us step past the two lines that set `len_lquote' and `len_rquote',
+and then examine the values of those variables.
+
+ (gdb) n
+ 539 len_rquote = strlen(lquote);
+ (gdb) n
+ 540 }
+ (gdb) p len_lquote
+ $3 = 9
+ (gdb) p len_rquote
+ $4 = 7
+
+That certainly looks wrong, assuming `len_lquote' and `len_rquote' are
+meant to be the lengths of `lquote' and `rquote' respectively. We can
+set them to better values using the `p' command, since it can print the
+value of any expression--and that expression can include subroutine
+calls and assignments.
+
+ (gdb) p len_lquote=strlen(lquote)
+ $5 = 7
+ (gdb) p len_rquote=strlen(rquote)
+ $6 = 9
+
+Is that enough to fix the problem of using the new quotes with the `m4'
+built-in `defn'? We can allow `m4' to continue executing with the `c'
+(`continue') command, and then try the example that caused trouble
+initially:
+
+ (gdb) c
+ Continuing.
+
+ define(baz,defn(<QUOTE>foo<UNQUOTE>))
+
+ baz
+ 0000
+
+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 `m4' exit by giving it an EOF as input:
+
+ C-d
+ Program exited normally.
+
+The message `Program exited normally.' is from GDB; it indicates `m4'
+has finished executing. We can end our GDB session with the GDB `quit'
+command.
+
+ (gdb) quit
+
+
+File: gdb.info, Node: Invocation, Next: Commands, Prev: Sample Session, Up: Top
+
+Getting In and Out of GDB
+*************************
+
+ This chapter discusses how to start GDB, and how to get out of it.
+(The essentials: type `gdb' to start GDB, and type `quit' or `C-d' to
+exit.)
+
+* Menu:
+
+* Invoking GDB:: How to start GDB
+* Quitting GDB:: How to quit GDB
+* Shell Commands:: How to use shell commands inside GDB
+
+
+File: gdb.info, Node: Invoking GDB, Next: Quitting GDB, Up: Invocation
+
+Invoking GDB
+============
+
+ Invoke GDB by running the program `gdb'. Once started, GDB reads
+commands from the terminal until you tell it to exit.
+
+ You can also run `gdb' with a variety of arguments and options, to
+specify more of your debugging environment at the outset.
+
+ 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.
+
+ The most usual way to start GDB is with one argument, specifying an
+executable program:
+
+ gdb PROGRAM
+
+You can also start with both an executable program and a core file
+specified:
+
+ gdb PROGRAM CORE
+
+ You can, instead, specify a process ID as a second argument, if you
+want to debug a running process:
+
+ gdb PROGRAM 1234
+
+would attach GDB to process `1234' (unless you also have a file named
+`1234'; GDB does check for a core file first).
+
+ Taking advantage of the second command-line argument requires a
+fairly complete operating system; when you use GDB 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.
+
+You can further control how GDB starts up by using command-line
+options. GDB itself can remind you of the options available.
+
+Type
+
+ gdb -help
+
+to display all available options and briefly describe their use (`gdb
+-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 `-x' option is
+used.
+
+* Menu:
+
+
+
+* File Options:: Choosing files
+* Mode Options:: Choosing modes
+
+
+File: gdb.info, Node: File Options, Next: Mode Options, Up: Invoking GDB
+
+Choosing files
+--------------
+
+ When GDB 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 `-se' and `-c'
+options respectively. (GDB reads the first argument that does not have
+an associated option flag as equivalent to the `-se' option followed by
+that argument; and the second argument that does not have an associated
+option flag, if any, as equivalent to the `-c' option followed by that
+argument.)
+
+ Many options have both long and short forms; both are shown in the
+following list. GDB 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 `--' rather than
+`-', though we illustrate the more usual convention.)
+
+`-symbols FILE'
+`-s FILE'
+ Read symbol table from file FILE.
+
+`-exec FILE'
+`-e FILE'
+ Use file FILE as the executable file to execute when appropriate,
+ and for examining pure data in conjunction with a core dump.
+
+`-se FILE'
+ Read symbol table from file FILE and use it as the executable file.
+
+`-core FILE'
+`-c FILE'
+ Use file FILE as a core dump to examine.
+
+`-c NUMBER'
+ Connect to process ID NUMBER, as with the `attach' command (unless
+ there is a file in core-dump format named NUMBER, in which case
+ `-c' specifies that file as a core dump to read).
+
+`-command FILE'
+`-x FILE'
+ Execute GDB commands from file FILE. *Note Command files: Command
+ Files.
+
+`-directory DIRECTORY'
+`-d DIRECTORY'
+ Add DIRECTORY to the path to search for source files.
+
+`-m'
+`-mapped'
+ *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
+ `mmap' system call, you can use this option to have GDB write the
+ symbols from your program into a reusable file in the current
+ directory. If the program you are debugging is called
+ `/tmp/fred', the mapped symbol file will be `./fred.syms'. Future
+ GDB debugging sessions will notice the presence of this file, and
+ will quickly map in symbol information from it, rather than reading
+ the symbol table from the executable program.
+
+ The `.syms' file is specific to the host machine where GDB is run.
+ It holds an exact image of the internal GDB symbol table. It
+ cannot be shared across multiple host platforms.
+
+`-r'
+`-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.
+
+ The `-mapped' and `-readnow' options are typically combined in order
+to build a `.syms' file that contains complete symbol information.
+(*Note Commands to specify files: Files, for information on `.syms'
+files.) A simple GDB invocation to do nothing but build a `.syms' file
+for future use is:
+
+ gdb -batch -nx -mapped -readnow programname
+
+
+File: gdb.info, Node: Mode Options, Prev: File Options, Up: Invoking GDB
+
+Choosing modes
+--------------
+
+ You can run GDB in various alternative modes--for example, in batch
+mode or quiet mode.
+
+`-nx'
+`-n'
+ Do not execute commands from any initialization files (normally
+ called `.gdbinit'). Normally, the commands in these files are
+ executed after all the command options and arguments have been
+ processed. *Note Command files: Command Files.
+
+`-quiet'
+`-q'
+ "Quiet". Do not print the introductory and copyright messages.
+ These messages are also suppressed in batch mode.
+
+`-batch'
+ Run in batch mode. Exit with status `0' after processing all the
+ command files specified with `-x' (and all commands from
+ initialization files, if not inhibited with `-n'). 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
+
+ Program exited normally.
+
+ (which is ordinarily issued whenever a program running under GDB
+ control terminates) is not issued when running in batch mode.
+
+`-cd DIRECTORY'
+ Run GDB using DIRECTORY as its working directory, instead of the
+ current directory.
+
+`-fullname'
+`-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 your program stops). This recognizable format
+ looks like two `\032' 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 `\032' characters
+ as a signal to display the source code for the frame.
+
+`-b BPS'
+ Set the line speed (baud rate or bits per second) of any serial
+ interface used by GDB for remote debugging.
+
+`-tty DEVICE'
+ Run using DEVICE for your program's standard input and output.
+
+
+File: gdb.info, Node: Quitting GDB, Next: Shell Commands, Prev: Invoking GDB, Up: Invocation
+
+Quitting GDB
+============
+
+`quit'
+ To exit GDB, use the `quit' command (abbreviated `q'), or type an
+ end-of-file character (usually `C-d').
+
+ An interrupt (often `C-c') will not exit from GDB, but rather will
+terminate the action of any GDB command that is in progress and return
+to GDB command level. It is safe to type the interrupt character at
+any time because GDB does not allow it to take effect until a time when
+it is safe.
+
+ If you have been using GDB to control an attached process or device,
+you can release it with the `detach' command (*note Debugging an
+already-running process: Attach.).
+
+
+File: gdb.info, Node: Shell Commands, Prev: Quitting GDB, Up: Invocation
+
+Shell commands
+==============
+
+ If you need to execute occasional shell commands during your
+debugging session, there is no need to leave or suspend GDB; you can
+just use the `shell' command.
+
+`shell COMMAND STRING'
+ Invoke a the standard shell to execute COMMAND STRING. If it
+ exists, the environment variable `SHELL' determines which shell to
+ run. Otherwise GDB uses `/bin/sh'.
+
+ The utility `make' is often needed in development environments. You
+do not have to use the `shell' command for this purpose in GDB:
+
+`make MAKE-ARGS'
+ Execute the `make' program with the specified arguments. This is
+ equivalent to `shell make MAKE-ARGS'.
+
+
+File: gdb.info, Node: Commands, Next: Running, Prev: Invocation, Up: Top
+
+GDB Commands
+************
+
+ You can abbreviate a GDB command to the first few letters of the
+command name, if that abbreviation is unambiguous; and you can repeat
+certain GDB commands by typing just RET. You can also use the TAB key
+to get GDB 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 GDB
+* Completion:: Command completion
+* Help:: How to ask GDB for help
+
+
+File: gdb.info, Node: Command Syntax, Next: Completion, Up: Commands
+
+Command syntax
+==============
+
+ A GDB 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 `step' accepts an argument which is the number of times to
+step, as in `step 5'. You can also use the `step' command with no
+arguments. Some command names do not allow any arguments.
+
+ GDB 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, `s' is specially defined as
+equivalent to `step' even though there are other commands whose names
+start with `s'. You can test abbreviations by using them as arguments
+to the `help' command.
+
+ A blank line as input to GDB (typing just RET) means to repeat the
+previous command. Certain commands (for example, `run') will not repeat
+this way; these are commands for which unintentional repetition might
+cause trouble and which you are unlikely to want to repeat.
+
+ The `list' and `x' commands, when you repeat them with RET,
+construct new arguments rather than repeating exactly as typed. This
+permits easy scanning of source or memory.
+
+ GDB can also use RET in another way: to partition lengthy output, in
+a way similar to the common utility `more' (*note Screen size: Screen
+Size.). Since it is easy to press one RET too many in this situation,
+GDB disables command repetition after any command that generates this
+sort of display.
+
+ Any text from a `#' to the end of the line is a comment; it does
+nothing. This is useful mainly in command files (*note Command files:
+Command Files.).
+
+
+File: gdb.info, Node: Completion, Next: Help, Prev: Command Syntax, Up: Commands
+
+Command completion
+==================
+
+ GDB 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 GDB
+commands, GDB subcommands, and the names of symbols in your program.
+
+ Press the TAB key whenever you want GDB to fill out the rest of a
+word. If there is only one possibility, GDB will fill in the word, and
+wait for you to finish the command (or press RET to enter it). For
+example, if you type
+
+ (gdb) info bre TAB
+
+GDB fills in the rest of the word `breakpoints', since that is the only
+`info' subcommand beginning with `bre':
+
+ (gdb) info breakpoints
+
+You can either press RET at this point, to run the `info breakpoints'
+command, or backspace and enter something else, if `breakpoints' does
+not look like the command you expected. (If you were sure you wanted
+`info breakpoints' in the first place, you might as well just type RET
+immediately after `info bre', to exploit command abbreviations rather
+than command completion).
+
+ If there is more than one possibility for the next word when you
+press TAB, GDB will sound a bell. You can either supply more
+characters and try again, or just press TAB a second time, and GDB will
+display all the possible completions for that word. For example, you
+might want to set a breakpoint on a subroutine whose name begins with
+`make_', but when you type `b make_TAB' GDB just sounds the bell.
+Typing TAB again will display all the function names in your program
+that begin with those characters, for example:
+
+ (gdb) b make_ TAB
+GDB sounds bell; press 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
+ (gdb) b make_
+
+After displaying the available possibilities, GDB copies your partial
+input (`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 `M-?' rather than pressing TAB twice. `M-?' means `META
+?'. You can type this either by holding down a key designated as the
+META shift on your keyboard (if there is one) while typing `?', or as
+ESC followed by `?'.
+
+ Sometimes the string you need, while logically a "word", may contain
+parentheses or other characters that GDB normally excludes from its
+notion of a word. To permit word completion to work in this situation,
+you may enclose words in `'' (single quote marks) in GDB commands.
+
+ 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 `name' that takes an `int'
+parameter, `name(int)', or the version that takes a `float' parameter,
+`name(float)'. To use the word-completion facilities in this
+situation, type a single quote `'' at the beginning of the function
+name. This alerts GDB that it may need to consider more information
+than usual when you press TAB or `M-?' to request word completion:
+
+ (gdb) b 'bubble( M-?
+ bubble(double,double) bubble(int,int)
+ (gdb) b 'bubble(
+
+ In some cases, GDB can tell that completing a name will require
+quotes. When this happens, GDB will insert the quote for you (while
+completing as much as it can) if you do not type the quote in the first
+place:
+
+ (gdb) b bub TAB
+GDB alters your input line to the following, and rings a bell:
+ (gdb) b 'bubble(
+
+In general, GDB 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.
+
+
+File: gdb.info, Node: Help, Prev: Completion, Up: Commands
+
+Getting help
+============
+
+ You can always ask GDB itself for information on its commands, using
+the command `help'.
+
+`help'
+`h'
+ You can use `help' (abbreviated `h') with no arguments to display
+ a short list of named classes of commands:
+
+ (gdb) 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.
+ (gdb)
+
+`help 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 `status':
+
+ (gdb) help status
+ Status inquiries.
+
+ List of commands:
+
+ 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.
+ (gdb)
+
+`help COMMAND'
+ With a command name as `help' argument, GDB will display a short
+ paragraph on how to use that command.
+
+ In addition to `help', you can use the GDB commands `info' and
+`show' to inquire about the state of your program, or the state of GDB
+itself. Each command supports many topics of inquiry; this manual
+introduces each of them in the appropriate context. The listings under
+`info' and under `show' in the Index point to all the sub-commands.
+*Note Index::.
+
+`info'
+ This command (abbreviated `i') is for describing the state of your
+ program. For example, you can list the arguments given to your
+ program with `info args', list the registers currently in use with
+ `info registers', or list the breakpoints you have set with `info
+ breakpoints'. You can get a complete list of the `info'
+ sub-commands with `help info'.
+
+`show'
+ In contrast, `show' is for describing the state of GDB itself.
+ You can change most of the things you can `show', by using the
+ related command `set'; for example, you can control what number
+ system is used for displays with `set radix', or simply inquire
+ which is currently in use with `show radix'.
+
+ To display all the settable parameters and their current values,
+ you can use `show' with no arguments; you may also use `info set'.
+ Both commands produce the same display.
+
+ Here are three miscellaneous `show' subcommands, all of which are
+exceptional in lacking corresponding `set' commands:
+
+`show version'
+ Show what version of GDB is running. You should include this
+ information in GDB bug-reports. If multiple versions of GDB are in
+ use at your site, you may occasionally want to determine which
+ version of GDB you are running; as GDB evolves, new commands are
+ introduced, and old ones may wither away. The version number is
+ also announced when you start GDB.
+
+`show copying'
+ Display information about permission for copying GDB.
+
+`show warranty'
+ Display the GNU "NO WARRANTY" statement.
+
+
+File: gdb.info, Node: Running, Next: Stopping, Prev: Commands, Up: Top
+
+Running Programs Under GDB
+**************************
+
+ When you run a program under GDB, you must first generate debugging
+information when you compile it. 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.
+
+* Menu:
+
+* Compilation:: Compiling for debugging
+* Starting:: Starting your program
+
+* 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
+
+
+File: gdb.info, Node: Compilation, Next: Starting, Up: Running
+
+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 `-g' option when you
+run the compiler.
+
+ Many C compilers are unable to handle the `-g' and `-O' options
+together. Using those compilers, you cannot generate optimized
+executables containing debugging information.
+
+ GCC, the GNU C compiler, supports `-g' with or without `-O', making
+it possible to debug optimized code. We recommend that you *always*
+use `-g' whenever you compile a program. You may think your program is
+correct, but there is no sense in pushing your luck.
+
+ When you debug a program compiled with `-g -O', remember that the
+optimizer is rearranging your code; the debugger will show 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, GDB will never see that variable--because
+the compiler optimizes it out of existence.
+
+ Some things do not work as well with `-g -O' as with just `-g',
+particularly on machines with instruction scheduling. If in doubt,
+recompile with `-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
+`-gg' for debugging information. GDB no longer supports this format;
+if your GNU C compiler has this option, do not use it.
+
+
+File: gdb.info, Node: Starting, Next: Arguments, Prev: Compilation, Up: Running
+
+Starting your program
+=====================
+
+`run'
+`r'
+ Use the `run' command to start your program under GDB. You must
+ first specify the program name (except on VxWorks) with an
+ argument to GDB (*note Getting In and Out of GDB: Invocation.), or
+ by using the `file' or `exec-file' command (*note Commands to
+ specify files: Files.).
+
+ If you are running your program in an execution environment that
+supports processes, `run' creates an inferior process and makes that
+process run your program. (In environments without processes, `run'
+jumps to the start of your program.)
+
+ The execution of a program is affected by certain information it
+receives from its superior. GDB provides ways to specify this
+information, which you must do *before* starting your program. (You
+can change it after starting your program, but such changes will only
+affect your program the next time you start it.) This information may
+be divided into four categories:
+
+The *arguments.*
+ Specify the arguments to give your program as the arguments of the
+ `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 `SHELL' environment variable. *Note
+ Your program's arguments: Arguments.
+
+The *environment.*
+ Your program normally inherits its environment from GDB, but you
+ can use the GDB commands `set environment' and `unset environment'
+ to change parts of the environment that will be given to your
+ program. *Note Your program's environment: Environment.
+
+The *working directory.*
+ Your program inherits its working directory from GDB. You can set
+ the GDB working directory with the `cd' command in GDB. *Note
+ Your program's working directory: Working Directory.
+
+The *standard input and output.*
+ Your program normally uses the same device for standard input and
+ standard output as GDB is using. You can redirect input and output
+ in the `run' command line, or you can use the `tty' command to set
+ a different device for your program. *Note Your program's input
+ and output: Input/Output.
+
+ *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, GDB is likely to wind up
+ debugging the wrong program.
+
+ When you issue the `run' command, your program begins to execute
+immediately. *Note Stopping and continuing: Stopping, 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 `print' or
+`call' commands. *Note Examining Data: Data.
+
+ If the modification time of your symbol file has changed since the
+last time GDB read its symbols, GDB will discard its symbol table and
+re-read it. When it does this, GDB tries to retain your current
+breakpoints.
+
+
+File: gdb.info, Node: Arguments, Next: Environment, Prev: Starting, Up: Running
+
+Your program's arguments
+========================
+
+ The arguments to your program can be specified by the arguments of
+the `run' command. They are passed to a shell, which expands wildcard
+characters and performs redirection of I/O, and thence to your program.
+Your `SHELL' environment variable (if it exists) specifies what shell
+GDB if you do not define `SHELL', GDB uses `/bin/sh'.
+
+ `run' with no arguments uses the same arguments used by the previous
+`run', or those set by the `set args' command.
+
+`set args'
+ Specify the arguments to be used the next time your program is
+ run. If `set args' has no arguments, `run' will execute your
+ program with no arguments. Once you have run your program with
+ arguments, using `set args' before the next `run' is the only way
+ to run it again without arguments.
+
+`show args'
+ Show the arguments to give your program when it is started.
+
+
+File: gdb.info, Node: Environment, Next: Working Directory, Prev: Arguments, Up: Running
+
+Your program's environment
+==========================
+
+ The "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 GDB over
+again.
+
+`path DIRECTORY'
+ Add DIRECTORY to the front of the `PATH' environment variable (the
+ search path for executables), for both GDB and your program. You
+ may specify several directory names, separated by `:' or
+ whitespace. If DIRECTORY is already in the path, it is moved to
+ the front, so it will be searched sooner.
+
+ You can use the string `$cwd' to refer to whatever is the current
+ working directory at the time GDB searches the path. If you use
+ `.' instead, it refers to the directory where you executed the
+ `path' command. GDB replaces `.' in the DIRECTORY argument (with
+ the current path) before adding DIRECTORY to the search path.
+
+`show paths'
+ Display the list of search paths for executables (the `PATH'
+ environment variable).
+
+`show environment [VARNAME]'
+ Print the value of environment variable VARNAME to be given to
+ your program when it starts. If you do not supply VARNAME, print
+ the names and values of all environment variables to be given to
+ your program. You can abbreviate `environment' as `env'.
+
+`set environment VARNAME [=] VALUE'
+ Set environment variable VARNAME to VALUE. The value changes for
+ your program only, not for GDB itself. VALUE may be any string;
+ the values of environment variables are just strings, and any
+ interpretation is supplied by your program itself. The VALUE
+ parameter is optional; if it is eliminated, the variable is set to
+ a null value.
+
+ For example, this command:
+
+ set env USER = foo
+
+ tells a Unix program, when subsequently run, that its user is named
+ `foo'. (The spaces around `=' are used for clarity here; they are
+ not actually required.)
+
+`unset environment VARNAME'
+ Remove variable VARNAME from the environment to be passed to your
+ program. This is different from `set env VARNAME ='; `unset
+ environment' removes the variable from the environment, rather
+ than assigning it an empty value.
+
+ *Warning:* GDB runs your program using the shell indicated by your
+`SHELL' environment variable if it exists (or `/bin/sh' if not). If
+your `SHELL' variable names a shell that runs an initialization
+file--such as `.cshrc' for C-shell, or `.bashrc' for BASH--any
+variables you set in that file will affect your program. You may wish
+to move setting of environment variables to files that are only run
+when you sign on, such as `.login' or `.profile'.
+
+
+File: gdb.info, Node: Working Directory, Next: Input/Output, Prev: Environment, Up: Running
+
+Your program's working directory
+================================
+
+ Each time you start your program with `run', it inherits its working
+directory from the current working directory of GDB. The GDB working
+directory is initially whatever it inherited from its parent process
+(typically the shell), but you can specify a new working directory in
+GDB with the `cd' command.
+
+ The GDB working directory also serves as a default for the commands
+that specify files for GDB to operate on. *Note Commands to specify
+files: Files.
+
+`cd DIRECTORY'
+ Set the GDB working directory to DIRECTORY.
+
+`pwd'
+ Print the GDB working directory.
+
+
+File: gdb.info, Node: Input/Output, Next: Attach, Prev: Working Directory, Up: Running
+
+Your program's input and output
+===============================
+
+ By default, the program you run under GDB does input and output to
+the same terminal that GDB uses. GDB 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.
+
+`info terminal'
+ Displays information recorded by GDB about the terminal modes your
+ program is using.
+
+ You can redirect your program's input and/or output using shell
+redirection with the `run' command. For example,
+
+ run > outfile
+
+starts your program, diverting its output to the file `outfile'.
+
+ Another way to specify where your program should do input and output
+is with the `tty' command. This command accepts a file name as
+argument, and causes this file to be the default for future `run'
+commands. It also resets the controlling terminal for the child
+process, for future `run' commands. For example,
+
+ tty /dev/ttyb
+
+directs that processes started with subsequent `run' commands default
+to do input and output on the terminal `/dev/ttyb' and have that as
+their controlling terminal.
+
+ An explicit redirection in `run' overrides the `tty' command's
+effect on the input/output device, but not its effect on the controlling
+terminal.
+
+ When you use the `tty' command or redirect input in the `run'
+command, only the input *for your program* is affected. The input for
+GDB still comes from your terminal.
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-2 b/gnu/usr.bin/gdb/doc/gdb.info-2
new file mode 100644
index 0000000..e8be2fa
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-2
@@ -0,0 +1,1165 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ 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.
+
+ 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.
+
+
+File: gdb.info, Node: Attach, Next: Kill Process, Prev: Input/Output, Up: Running
+
+Debugging an already-running process
+====================================
+
+`attach PROCESS-ID'
+ This command attaches to a running process--one that was started
+ outside GDB. (`info files' will show 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 `ps' utility, or with
+ the `jobs -l' shell command.
+
+ `attach' will not repeat if you press RET a second time after
+ executing the command.
+
+ To use `attach', your program must be running in an environment
+which supports processes; for example, `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 `attach', you should first use the `file' command to
+specify the program running in the process and load its symbol table.
+*Note Commands to Specify Files: Files.
+
+ The first thing GDB does after arranging to debug the specified
+process is to stop it. You can examine and modify an attached process
+with all the GDB commands that are ordinarily available when you start
+processes with `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 `continue' command after attaching
+GDB to the process.
+
+`detach'
+ When you have finished debugging the attached process, you can use
+ the `detach' command to release it from GDB control. Detaching
+ the process continues its execution. After the `detach' command,
+ that process and GDB become completely independent once more, and
+ you are ready to `attach' another process or start one with `run'.
+ `detach' will not repeat if you press RET again after executing
+ the command.
+
+ If you exit GDB or use the `run' command while you have an attached
+process, you kill that process. By default, you will be asked for
+confirmation if you try to do either of these things; you can control
+whether or not you need to confirm by using the `set confirm' command
+(*note Optional warnings and messages: Messages/Warnings.).
+
+
+File: gdb.info, Node: Kill Process, Next: Process Information, Prev: Attach, Up: Running
+
+Killing the child process
+=========================
+
+`kill'
+ Kill the child process in which your program is running under GDB.
+
+ This command is useful if you wish to debug a core dump instead of a
+running process. GDB ignores any core dump file while your program is
+running.
+
+ On some operating systems, a program cannot be executed outside GDB
+while you have breakpoints set on it inside GDB. You can use the
+`kill' command in this situation to permit running your program outside
+the debugger.
+
+ The `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 `run', GDB will notice that the file has changed, and
+will re-read the symbol table (while trying to preserve your current
+breakpoint settings).
+
+
+File: gdb.info, Node: Process Information, Prev: Kill Process, Up: Running
+
+Additional process information
+==============================
+
+ Some operating systems provide a facility called `/proc' that can be
+used to examine the image of a running process using file-system
+subroutines. If GDB is configured for an operating system with this
+facility, the command `info proc' is available to report on several
+kinds of information about the process running your program.
+
+`info proc'
+ Summarize available information about the process.
+
+`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.
+
+`info proc times'
+ Starting time, user CPU time, and system CPU time for your program
+ and its children.
+
+`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.
+
+`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.
+
+`info proc all'
+ Show all the above information about the process.
+
+
+File: gdb.info, Node: Stopping, Next: Stack, Prev: Running, Up: Top
+
+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 GDB, your program may stop for any of several reasons, such as
+a signal, a breakpoint, or reaching a new line after a GDB command such
+as `step'. You may then examine and change variables, set new
+breakpoints or remove old ones, and then continue execution. Usually,
+the messages shown by GDB provide ample explanation of the status of
+your program--but you can also explicitly request this information at
+any time.
+
+`info program'
+ Display information about the status of your program: whether it is
+ running or not, what process it is, and why it stopped.
+
+* Menu:
+
+
+* Breakpoints:: Breakpoints, watchpoints, and exceptions
+
+
+* Continuing and Stepping:: Resuming execution
+
+* Signals:: Signals
+
+
+File: gdb.info, Node: Breakpoints, Next: Continuing and Stepping, Up: Stopping
+
+Breakpoints, watchpoints, and exceptions
+========================================
+
+ A "breakpoint" makes your program stop whenever a certain point in
+the program is reached. For each breakpoint, you can add various
+conditions to control in finer detail whether your program will stop.
+You can set breakpoints with the `break' command and its variants
+(*note Setting breakpoints: Set Breaks.), to specify the place where
+your program should stop by line number, function name or exact address
+in the program. In languages with exception handling (such as GNU
+C++), you can also set breakpoints where an exception is raised (*note
+Breakpoints and exceptions: Exception Handling.).
+
+ A "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 (*note Setting watchpoints: Set 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 GDB stops at a breakpoint. *Note Automatic
+display: Auto Display.
+
+ GDB 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 "enabled" or "disabled"; if disabled, it has no
+effect on your program until you enable it again.
+
+* Menu:
+
+* Set Breaks:: Setting breakpoints
+* Set Watchpoints:: Setting watchpoints
+
+* Exception Handling:: Breakpoints and exceptions
+
+* Delete Breaks:: Deleting breakpoints
+* Disabling:: Disabling breakpoints
+* Conditions:: Break conditions
+* Break Commands:: Breakpoint command lists
+
+* Breakpoint Menus:: Breakpoint menus
+
+* Error in Breakpoints:: "Cannot insert breakpoints"
+
+
+File: gdb.info, Node: Set Breaks, Next: Set Watchpoints, Up: Breakpoints
+
+Setting breakpoints
+-------------------
+
+ Breakpoints are set with the `break' command (abbreviated `b'). The
+debugger convenience variable `$bpnum' records the number of the
+beakpoint you've set most recently; see *Note Convenience variables:
+Convenience Vars, for a discussion of what you can do with convenience
+variables.
+
+ You have several ways to say where the breakpoint should go.
+
+`break FUNCTION'
+ Set a breakpoint at entry to function FUNCTION. When using source
+ languages that permit overloading of symbols, such as C++,
+ FUNCTION may refer to more than one possible place to break.
+ *Note Breakpoint menus: Breakpoint Menus, for a discussion of that
+ situation.
+
+`break +OFFSET'
+`break -OFFSET'
+ Set a breakpoint some number of lines forward or back from the
+ position at which execution stopped in the currently selected
+ frame.
+
+`break LINENUM'
+ Set a breakpoint at line LINENUM in the current source file. That
+ file is the last file whose source text was printed. This
+ breakpoint will stop your program just before it executes any of
+ the code on that line.
+
+`break FILENAME:LINENUM'
+ Set a breakpoint at line LINENUM in source file FILENAME.
+
+`break FILENAME:FUNCTION'
+ Set a breakpoint at entry to function FUNCTION found in file
+ FILENAME. Specifying a file name as well as a function name is
+ superfluous except when multiple files contain similarly named
+ functions.
+
+`break *ADDRESS'
+ Set a breakpoint at address ADDRESS. You can use this to set
+ breakpoints in parts of your program which do not have debugging
+ information or source files.
+
+`break'
+ When called without any arguments, `break' sets a breakpoint at
+ the next instruction to be executed in the selected stack frame
+ (*note Examining the Stack: Stack.). In any selected frame but the
+ innermost, this will cause your program to stop as soon as control
+ returns to that frame. This is similar to the effect of a
+ `finish' command in the frame inside the selected frame--except
+ that `finish' does not leave an active breakpoint. If you use
+ `break' without an argument in the innermost frame, GDB will stop
+ the next time it reaches the current location; this may be useful
+ inside loops.
+
+ GDB 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.
+
+`break ... if COND'
+ Set a breakpoint with condition COND; evaluate the expression COND
+ each time the breakpoint is reached, and stop only if the value is
+ nonzero--that is, if COND evaluates as true. `...' stands for one
+ of the possible arguments described above (or no argument)
+ specifying where to break. *Note Break conditions: Conditions,
+ for more information on breakpoint conditions.
+
+`tbreak ARGS'
+ Set a breakpoint enabled only for one stop. ARGS are the same as
+ for the `break' command, and the breakpoint is set in the same
+ way, but the breakpoint is automatically disabled after the first
+ time your program stops there. *Note Disabling breakpoints:
+ Disabling.
+
+`rbreak REGEX'
+ Set breakpoints on all functions matching the regular expression
+ 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 `break' command. They can be deleted, disabled, made
+ conditional, etc., in the standard ways.
+
+ When debugging C++ programs, `rbreak' is useful for setting
+ breakpoints on overloaded functions that are not members of any
+ special classes.
+
+`info breakpoints [N]'
+`info break [N]'
+`info watchpoints [N]'
+ Print a table of all breakpoints and watchpoints set and not
+ deleted, with the following columns for each breakpoint:
+
+ *Breakpoint Numbers*
+ *Type*
+ Breakpoint or watchpoint.
+
+ *Disposition*
+ Whether the breakpoint is marked to be disabled or deleted
+ when hit.
+
+ *Enabled or Disabled*
+ Enabled breakpoints are marked with `y'. `n' marks
+ breakpoints that are not enabled.
+
+ *Address*
+ Where the breakpoint is in your program, as a memory address
+
+ *What*
+ Where the breakpoint is in the source for your program, as a
+ file and line number.
+
+ If a breakpoint is conditional, `info break' shows the condition on
+ the line following the affected breakpoint; breakpoint commands,
+ if any, are listed after that.
+
+ `info break' with a breakpoint number N as argument lists only
+ that breakpoint. The convenience variable `$_' and the default
+ examining-address for the `x' command are set to the address of
+ the last breakpoint listed (*note Examining memory: Memory.).
+
+ GDB 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 (*note Break
+conditions: Conditions.).
+
+ GDB itself sometimes sets breakpoints in your program for special
+purposes, such as proper handling of `longjmp' (in C programs). These
+internal breakpoints are assigned negative numbers, starting with `-1';
+`info breakpoints' does not display them.
+
+ You can see these breakpoints with the GDB maintenance command
+`maint info breakpoints'.
+
+`maint info breakpoints'
+ Using the same format as `info breakpoints', display both the
+ breakpoints you've set explicitly, and those GDB is using for
+ internal purposes. Internal breakpoints are shown with negative
+ breakpoint numbers. The type column identifies what kind of
+ breakpoint is shown:
+
+ `breakpoint'
+ Normal, explicitly set breakpoint.
+
+ `watchpoint'
+ Normal, explicitly set watchpoint.
+
+ `longjmp'
+ Internal breakpoint, used to handle correctly stepping through
+ `longjmp' calls.
+
+ `longjmp resume'
+ Internal breakpoint at the target of a `longjmp'.
+
+ `until'
+ Temporary internal breakpoint used by the GDB `until' command.
+
+ `finish'
+ Temporary internal breakpoint used by the GDB `finish'
+ command.
+
+
+File: gdb.info, Node: Set Watchpoints, Next: Exception Handling, Prev: Set Breaks, Up: Breakpoints
+
+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. Some
+processors provide special hardware to support watchpoint evaluation;
+future releases of GDB will use such hardware if it is available.
+
+`watch EXPR'
+ Set a watchpoint for an expression.
+
+`info watchpoints'
+ This command prints a list of watchpoints and breakpoints; it is
+ the same as `info break'.
+
+
+File: gdb.info, Node: Exception Handling, Next: Delete Breaks, Prev: Set Watchpoints, Up: Breakpoints
+
+Breakpoints and exceptions
+--------------------------
+
+ Some languages, such as GNU C++, implement exception handling. You
+can use GDB 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.
+
+`catch EXCEPTIONS'
+ You can set breakpoints at active exception handlers by using the
+ `catch' command. EXCEPTIONS is a list of names of exceptions to
+ catch.
+
+ You can use `info catch' to list active exception handlers. *Note
+Information about a frame: Frame Info.
+
+ There are currently some limitations to exception handling in GDB.
+These will be corrected in a future release.
+
+ * If you call a function interactively, GDB 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
+ GDB is listening for, or exits.
+
+ * You cannot raise an exception interactively.
+
+ * You cannot interactively install an exception handler.
+
+ Sometimes `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 *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 `__raise_exception' which
+has the following ANSI C interface:
+
+ /* ADDR is where the exception identifier is stored.
+ ID is the exception identifier. */
+ void __raise_exception (void **ADDR, void *ID);
+
+To make the debugger catch all exceptions before any stack unwinding
+takes place, set a breakpoint on `__raise_exception' (*note
+Breakpoints; watchpoints; and exceptions: Breakpoints.).
+
+ With a conditional breakpoint (*note Break conditions: Conditions.)
+that depends on the value of 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.
+
+
+File: gdb.info, Node: Delete Breaks, Next: Disabling, Prev: Exception Handling, Up: Breakpoints
+
+Deleting breakpoints
+--------------------
+
+ 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 "deleting" the breakpoint. A breakpoint that has been
+deleted no longer exists; it is forgotten.
+
+ With the `clear' command you can delete breakpoints according to
+where they are in your program. With the `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. GDB
+automatically ignores breakpoints on the first instruction to be
+executed when you continue execution without changing the execution
+address.
+
+`clear'
+ Delete any breakpoints at the next instruction to be executed in
+ the selected stack frame (*note Selecting a frame: Selection.).
+ When the innermost frame is selected, this is a good way to delete
+ a breakpoint where your program just stopped.
+
+`clear FUNCTION'
+`clear FILENAME:FUNCTION'
+ Delete any breakpoints set at entry to the function FUNCTION.
+
+`clear LINENUM'
+`clear FILENAME:LINENUM'
+ Delete any breakpoints set at or within the code of the specified
+ line.
+
+`delete [breakpoints] [BNUMS...]'
+ Delete the breakpoints or watchpoints of the numbers specified as
+ arguments. If no argument is specified, delete all breakpoints
+ (GDB asks confirmation, unless you have `set confirm off'). You
+ can abbreviate this command as `d'.
+
+
+File: gdb.info, Node: Disabling, Next: Conditions, Prev: Delete Breaks, Up: Breakpoints
+
+Disabling breakpoints
+---------------------
+
+ Rather than deleting a breakpoint or watchpoint, you might prefer to
+"disable" it. This makes the breakpoint inoperative as if it had been
+deleted, but remembers the information on the breakpoint so that you
+can "enable" it again later.
+
+ You disable and enable breakpoints and watchpoints with the `enable'
+and `disable' commands, optionally specifying one or more breakpoint
+numbers as arguments. Use `info break' or `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:
+
+ * Enabled. The breakpoint will stop your program. A breakpoint set
+ with the `break' command starts out in this state.
+
+ * Disabled. The breakpoint has no effect on your program.
+
+ * Enabled once. The breakpoint will stop your program, but when it
+ does so it will become disabled. A breakpoint set with the
+ `tbreak' command starts out in this state.
+
+ * Enabled for deletion. The breakpoint will stop your program, but
+ immediately after it does so it will be deleted permanently.
+
+ You can use the following commands to enable or disable breakpoints
+and watchpoints:
+
+`disable [breakpoints] [BNUMS...]'
+ 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 `disable' as `dis'.
+
+`enable [breakpoints] [BNUMS...]'
+ Enable the specified breakpoints (or all defined breakpoints).
+ They become effective once again in stopping your program.
+
+`enable [breakpoints] once BNUMS...'
+ Enable the specified breakpoints temporarily. Each will be
+ disabled again the next time it stops your program.
+
+`enable [breakpoints] delete BNUMS...'
+ Enable the specified breakpoints to work once and then die. Each
+ of the breakpoints will be deleted the next time it stops your
+ program.
+
+ Save for a breakpoint set with `tbreak' (*note Setting breakpoints:
+Set Breaks.), breakpoints that you set are initially enabled;
+subsequently, they become disabled or enabled only when you use one of
+the commands above. (The command `until' can set and delete a
+breakpoint of its own, but it will not change the state of your other
+breakpoints; see *Note Continuing and stepping: Continuing and
+Stepping.)
+
+
+File: gdb.info, Node: Conditions, Next: Break Commands, Prev: Disabling, Up: Breakpoints
+
+Break conditions
+----------------
+
+ The simplest sort of breakpoint breaks every time your program
+reaches a specified place. You can also specify a "condition" for a
+breakpoint. A condition is just a Boolean expression in your
+programming language (*note 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 *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 ASSERT, you should set the
+condition `! 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, GDB 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 (*note Breakpoint
+command lists: Break Commands.).
+
+ Break conditions can be specified when a breakpoint is set, by using
+`if' in the arguments to the `break' command. *Note Setting
+breakpoints: Set Breaks. They can also be changed at any time with the
+`condition' command. The `watch' command does not recognize the `if'
+keyword; `condition' is the only way to impose a further condition on a
+watchpoint.
+
+`condition BNUM EXPRESSION'
+ Specify EXPRESSION as the break condition for breakpoint or
+ watchpoint number BNUM. From now on, this breakpoint will stop
+ your program only if the value of EXPRESSION is true (nonzero, in
+ C). When you use `condition', GDB checks EXPRESSION immediately
+ for syntactic correctness, and to determine whether symbols in it
+ have referents in the context of your breakpoint. GDB does not
+ actually evaluate EXPRESSION at the time the `condition' command
+ is given, however. *Note Expressions: Expressions.
+
+`condition BNUM'
+ Remove the condition from breakpoint number BNUM. It becomes an
+ ordinary unconditional 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 "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
+N, the breakpoint will not stop the next N times it is reached.
+
+`ignore BNUM COUNT'
+ Set the ignore count of breakpoint number BNUM to COUNT. The next
+ COUNT times the breakpoint is reached, your program's execution
+ will not stop; other than to decrement the ignore count, GDB takes
+ no action.
+
+ To make the breakpoint stop the next time it is reached, specify a
+ count of zero.
+
+ When you use `continue' to resume execution of your program from a
+ breakpoint, you can specify an ignore count directly as an
+ argument to `continue', rather than using `ignore'. *Note
+ 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, the
+ condition will be checked.
+
+ You could achieve the effect of the ignore count with a condition
+ such as `$foo-- <= 0' using a debugger convenience variable that
+ is decremented each time. *Note Convenience variables:
+ Convenience Vars.
+
+
+File: gdb.info, Node: Break Commands, Next: Breakpoint Menus, Prev: Conditions, Up: Breakpoints
+
+Breakpoint command lists
+------------------------
+
+ 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.
+
+`commands [BNUM]'
+`... COMMAND-LIST ...'
+`end'
+ Specify a list of commands for breakpoint number BNUM. The
+ commands themselves appear on the following lines. Type a line
+ containing just `end' to terminate the commands.
+
+ To remove all commands from a breakpoint, type `commands' and
+ follow it immediately with `end'; that is, give no commands.
+
+ With no BNUM argument, `commands' refers to the last breakpoint or
+ watchpoint set (not to the breakpoint most recently encountered).
+
+ Pressing RET as a means of repeating the last GDB command is
+disabled within a COMMAND-LIST.
+
+ You can use breakpoint commands to start your program up again.
+Simply use the `continue' command, or `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 `next' or `step'), you may encounter another
+breakpoint--which could have its own command list, leading to
+ambiguities about which list to execute.
+
+ If the first command you specify in a command list is `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
+will see no sign that the breakpoint was reached. `silent' is
+meaningful only at the beginning of a breakpoint command list.
+
+ The commands `echo', `output', and `printf' allow you to print
+precisely controlled output, and are often useful in silent
+breakpoints. *Note Commands for controlled output: Output.
+
+ For example, here is how you could use breakpoint commands to print
+the value of `x' at entry to `foo' whenever `x' is positive.
+
+ break foo if x>0
+ commands
+ silent
+ printf "x is %d\n",x
+ cont
+ end
+
+ 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 `continue' command so
+that your program does not stop, and start with the `silent' command so
+that no output is produced. Here is an example:
+
+ break 403
+ commands
+ silent
+ set x = y + 4
+ cont
+ end
+
+
+File: gdb.info, Node: Breakpoint Menus, Next: Error in Breakpoints, Prev: Break Commands, Up: Breakpoints
+
+Breakpoint menus
+----------------
+
+ Some programming languages (notably C++) permit a single function
+name to be defined several times, for application in different contexts.
+This is called "overloading". When a function name is overloaded,
+`break FUNCTION' is not enough to tell GDB where you want a breakpoint.
+If you realize this will be a problem, you can use something like
+`break FUNCTION(TYPES)' to specify which particular version of the
+function you want. Otherwise, GDB offers you a menu of numbered
+choices for different possible breakpoints, and waits for your
+selection with the prompt `>'. The first two options are always `[0]
+cancel' and `[1] all'. Typing `1' sets a breakpoint at each definition
+of FUNCTION, and typing `0' aborts the `break' command without setting
+any new breakpoints.
+
+ For example, the following session excerpt shows an attempt to set a
+breakpoint at the overloaded symbol `String::after'. We choose three
+particular definitions of that function name:
+
+ (gdb) 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.
+ (gdb)
+
+
+File: gdb.info, Node: Error in Breakpoints, Prev: Breakpoint Menus, Up: Breakpoints
+
+"Cannot insert breakpoints"
+---------------------------
+
+ 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 GDB to stop the other process.
+
+ When this happens, you have three ways to proceed:
+
+ 1. Remove or disable the breakpoints, then continue.
+
+ 2. Suspend GDB, and copy the file containing your program to a new
+ name. Resume GDB and use the `exec-file' command to specify that
+ GDB should run your program under that name. Then start your
+ program again.
+
+ 3. Relink your program so that the text segment is nonsharable, using
+ the linker option `-N'. The operating system limitation may not
+ apply to nonsharable executables.
+
+
+File: gdb.info, Node: Continuing and Stepping, Next: Signals, Prev: Breakpoints, Up: Stopping
+
+Continuing and stepping
+=======================
+
+ "Continuing" means resuming program execution until your program
+completes normally. In contrast, "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 a breakpoint or a signal. (If due
+to a signal, you may want to use `handle', or use `signal 0' to resume
+execution. *Note Signals: Signals.)
+
+`continue [IGNORE-COUNT]'
+`c [IGNORE-COUNT]'
+`fg [IGNORE-COUNT]'
+ Resume program execution, at the address where your program last
+ stopped; any breakpoints set at that address are bypassed. The
+ optional argument IGNORE-COUNT allows you to specify a further
+ number of times to ignore a breakpoint at this location; its
+ effect is like that of `ignore' (*note Break conditions:
+ Conditions.).
+
+ The argument IGNORE-COUNT is meaningful only when your program
+ stopped due to a breakpoint. At other times, the argument to
+ `continue' is ignored.
+
+ The synonyms `c' and `fg' are provided purely for convenience, and
+ have exactly the same behavior as `continue'.
+
+ To resume execution at a different place, you can use `return'
+(*note Returning from a function: Returning.) to go back to the calling
+function; or `jump' (*note Continuing at a different address: Jumping.)
+to go to an arbitrary location in your program.
+
+ A typical technique for using stepping is to set a breakpoint (*note
+Breakpoints; watchpoints; and exceptions: Breakpoints.) 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.
+
+`step'
+ Continue running your program until control reaches a different
+ source line, then stop it and return control to GDB. This command
+ is abbreviated `s'.
+
+ *Warning:* If you use the `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.
+
+`step COUNT'
+ Continue running as in `step', but do so COUNT times. If a
+ breakpoint is reached, or a signal not related to stepping occurs
+ before COUNT steps, stepping stops right away.
+
+`next [COUNT]'
+ Continue to the next source line in the current (innermost) stack
+ frame. Similar to `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 `next' command was given. This
+ command is abbreviated `n'.
+
+ An argument COUNT is a repeat count, as for `step'.
+
+ `next' within a function that lacks debugging information acts like
+ `step', but any function calls appearing within the code of the
+ function are executed without stopping.
+
+`finish'
+ Continue running until just after function in the selected stack
+ frame returns. Print the returned value (if any).
+
+ Contrast this with the `return' command (*note Returning from a
+ function: Returning.).
+
+`until'
+`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
+ `next' command, except that when `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, `until' will cause your program to continue
+ execution until the loop is exited. In contrast, a `next' command
+ at the end of a loop will simply step back to the beginning of the
+ loop, which would force you to step through the next iteration.
+
+ `until' always stops your program if it attempts to exit the
+ current stack frame.
+
+ `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 `f'
+ (`frame') command shows that execution is stopped at line `206';
+ yet when we use `until', we get to line `195':
+
+ (gdb) f
+ #0 main (argc=4, argv=0xf7fffae8) at m4.c:206
+ 206 expand_input();
+ (gdb) until
+ 195 for ( ; argc > 0; NEXTARG) {
+
+ 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 `for'-loop is
+ written before the body of the loop. The `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.
+
+ `until' with no argument works by means of single instruction
+ stepping, and hence is slower than `until' with an argument.
+
+`until LOCATION'
+`u LOCATION'
+ Continue running your program until either the specified location
+ is reached, or the current stack frame returns. LOCATION is any of
+ the forms of argument acceptable to `break' (*note Setting
+ breakpoints: Set Breaks.). This form of the command uses
+ breakpoints, and hence is quicker than `until' without an argument.
+
+`stepi'
+`si'
+ Execute one machine instruction, then stop and return to the
+ debugger.
+
+ It is often useful to do `display/i $pc' when stepping by machine
+ instructions. This will cause the next instruction to be executed
+ to be displayed automatically at each stop. *Note Automatic
+ display: Auto Display.
+
+ An argument is a repeat count, as in `step'.
+
+`nexti'
+`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 `next'.
+
+
+File: gdb.info, Node: Signals, Prev: Continuing and Stepping, Up: Stopping
+
+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 `SIGINT' is the signal
+a program gets when you type an interrupt (often `C-c'); `SIGSEGV' is
+the signal a program gets from referencing a place in memory far away
+from all the areas in use; `SIGALRM' occurs when the alarm clock timer
+goes off (which happens only if your program has requested an alarm).
+
+ Some signals, including `SIGALRM', are a normal part of the
+functioning of your program. Others, such as `SIGSEGV', indicate
+errors; these signals are "fatal" (kill your program immediately) if the
+program has not specified in advance some other way to handle the
+signal. `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.
+
+ GDB has the ability to detect any occurrence of a signal in your
+program. You can tell GDB in advance what to do for each kind of
+signal.
+
+ Normally, GDB is set up to ignore non-erroneous signals like
+`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 `handle'
+command.
+
+`info signals'
+ Print a table of all the kinds of signals and how GDB has been
+ told to handle each one. You can use this to see the signal
+ numbers of all the defined types of signals.
+
+`handle SIGNAL KEYWORDS...'
+ Change the way GDB handles signal SIGNAL. SIGNAL can be the
+ number of a signal or its name (with or without the `SIG' at the
+ beginning). The KEYWORDS say what change to make.
+
+ The keywords allowed by the `handle' command can be abbreviated.
+Their full names are:
+
+`nostop'
+ GDB should not stop your program when this signal happens. It may
+ still print a message telling you that the signal has come in.
+
+`stop'
+ GDB should stop your program when this signal happens. This
+ implies the `print' keyword as well.
+
+`print'
+ GDB should print a message when this signal happens.
+
+`noprint'
+ GDB should not mention the occurrence of the signal at all. This
+ implies the `nostop' keyword as well.
+
+`pass'
+ GDB should allow your program to see this signal; your program
+ will be able to handle the signal, or may be terminated if the
+ signal is fatal and not handled.
+
+`nopass'
+ GDB should not allow your program to see this signal.
+
+ When a signal stops your program, the signal is not visible until you
+continue. Your program will see the signal then, if `pass' is in
+effect for the signal in question *at that time*. In other words,
+after GDB reports a signal, you can use the `handle' command with
+`pass' or `nopass' to control whether that signal will be seen by your
+program when you later continue it.
+
+ You can also use the `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 `signal 0'. *Note Giving your program a signal:
+Signaling.
+
+
+File: gdb.info, Node: Stack, Next: Source, Prev: Stopping, Up: Top
+
+Examining the Stack
+*******************
+
+ When your program has stopped, the first thing you need to know is
+where it stopped and how it got there.
+
+ 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 "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
+"call stack".
+
+ When your program stops, the GDB commands for examining the stack
+allow you to see all of this information.
+
+ One of the stack frames is "selected" by GDB and many GDB commands
+refer implicitly to the selected frame. In particular, whenever you
+ask GDB for the value of a variable in your program, the value is found
+in the selected frame. There are special GDB commands to select
+whichever frame you are interested in.
+
+ When your program stops, GDB automatically selects the currently
+executing frame and describes it briefly as the `frame' command does
+(*note Information about a frame: Frame Info.).
+
+* Menu:
+
+* Frames:: Stack frames
+* Backtrace:: Backtraces
+* Selection:: Selecting a frame
+* Frame Info:: Information on a frame
+
+* MIPS Stack:: MIPS machines and the function stack
+
+
+File: gdb.info, Node: Frames, Next: Backtrace, Up: Stack
+
+Stack frames
+============
+
+ The call stack is divided up into contiguous pieces called "stack
+frames", or "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.
+
+ When your program is started, the stack has only one frame, that of
+the function `main'. This is called the "initial" frame or the
+"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 "innermost" frame. This
+is the most recently created of all the stack frames that still exist.
+
+ 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 "frame pointer register"
+while execution is going on in that frame.
+
+ GDB 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 GDB to give you a way of designating stack frames in GDB
+commands.
+
+ Some compilers provide a way to compile functions so that they
+operate without stack frames. (For example, the `gcc' option
+`-fomit-frame-pointer' will generate functions without a frame.) This
+is occasionally done with heavily used library functions to save the
+frame setup time. GDB has limited facilities for dealing with these
+function invocations. If the innermost function invocation has no
+stack frame, GDB will nevertheless regard it as though it had a
+separate frame, which is numbered zero as usual, allowing correct
+tracing of the function call chain. However, GDB has no provision for
+frameless functions elsewhere in the stack.
+
+
+File: gdb.info, Node: Backtrace, Next: Selection, Prev: Frames, Up: Stack
+
+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.
+
+`backtrace'
+`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 `C-c'.
+
+`backtrace N'
+`bt N'
+ Similar, but print only the innermost N frames.
+
+`backtrace -N'
+`bt -N'
+ Similar, but print only the outermost N frames.
+
+ The names `where' and `info stack' (abbreviated `info s') are
+additional aliases for `backtrace'.
+
+ Each line in the backtrace shows the frame number and the function
+name. The program counter value is also shown--unless you use `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 `bt
+3', so it shows the innermost three frames.
+
+ #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...)
+
+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 `993' of `builtin.c'.
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-3 b/gnu/usr.bin/gdb/doc/gdb.info-3
new file mode 100644
index 0000000..aea5862
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-3
@@ -0,0 +1,1264 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ 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.
+
+ 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.
+
+
+File: gdb.info, Node: Selection, Next: Frame Info, Prev: Backtrace, Up: Stack
+
+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.
+
+`frame N'
+`f N'
+ Select frame number 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 `main'.
+
+`frame ADDR'
+`f ADDR'
+ Select the frame at address ADDR. This is useful mainly if the
+ chaining of stack frames has been damaged by a bug, making it
+ impossible for GDB to assign numbers properly to all frames. In
+ addition, this can be useful when your program has multiple stacks
+ and switches between them.
+
+ On the SPARC architecture, `frame' needs two addresses to select
+ an arbitrary frame: a frame pointer and a stack pointer.
+
+`up N'
+ Move N frames up the stack. For positive numbers N, this advances
+ toward the outermost frame, to higher frame numbers, to frames
+ that have existed longer. N defaults to one.
+
+`down N'
+ Move N frames down the stack. For positive numbers N, this
+ advances toward the innermost frame, to lower frame numbers, to
+ frames that were created more recently. N defaults to one. You
+ may abbreviate `down' as `do'.
+
+ 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.
+
+ For example:
+ (gdb) up
+ #1 0x22f0 in main (argc=1, argv=0xf7fffbf4, env=0xf7fffbfc)
+ at env.c:10
+ 10 read_input_file (argv[i]);
+
+ After such a printout, the `list' command with no arguments will
+print ten lines centered on the point of execution in the frame. *Note
+Printing source lines: List.
+
+`up-silently N'
+`down-silently N'
+ These two commands are variants of `up' and `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
+ GDB command scripts, where the output might be unnecessary and
+ distracting.
+
+
+File: gdb.info, Node: Frame Info, Next: MIPS Stack, Prev: Selection, Up: Stack
+
+Information about a frame
+=========================
+
+ There are several other commands to print information about the
+selected stack frame.
+
+`frame'
+`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 `f'. With an
+ argument, this command is used to select a stack frame. *Note
+ Selecting a frame: Selection.
+
+`info frame'
+`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.
+
+`info frame ADDR'
+`info f ADDR'
+ Print a verbose description of the frame at address ADDR, without
+ selecting that frame. The selected frame remains unchanged by
+ this command.
+
+`info args'
+ Print the arguments of the selected frame, each on a separate line.
+
+`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.
+
+`info catch'
+ 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
+ `up', `down', or `frame' commands); then type `info catch'. *Note
+ Breakpoints and exceptions: Exception Handling.
+
+
+File: gdb.info, Node: MIPS Stack, Prev: Frame Info, Up: Stack
+
+MIPS machines and the function stack
+====================================
+
+ MIPS based computers use an unusual stack frame, which sometimes
+requires GDB to search backward in the object code to find the
+beginning of a function.
+
+ To improve response time (especially for embedded applications, where
+GDB 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:
+
+`set heuristic-fence-post LIMIT'
+ Restrict GDBN to examining at most LIMIT bytes in its search for
+ the beginning of a function. A value of `0' (the default) means
+ there is no limit.
+
+`show heuristic-fence-post'
+ Display the current limit.
+
+These commands are available *only* when GDB is configured for
+debugging programs on MIPS processors.
+
+
+File: gdb.info, Node: Source, Next: Data, Prev: Stack, Up: Top
+
+Examining Source Files
+**********************
+
+ GDB can print parts of your program's source, since the debugging
+information recorded in the program tells GDB what source files were
+used to build it. When your program stops, GDB spontaneously prints
+the line where it stopped. Likewise, when you select a stack frame
+(*note Selecting a frame: Selection.), GDB prints the line where
+execution in that frame has stopped. You can print other portions of
+source files by explicit command.
+
+ If you use GDB through its GNU Emacs interface, you may prefer to use
+Emacs facilities to view source; *note Using GDB under GNU Emacs:
+Emacs..
+
+* Menu:
+
+* List:: Printing source lines
+
+* Search:: Searching source files
+
+* Source Path:: Specifying source directories
+* Machine Code:: Source and machine code
+
+
+File: gdb.info, Node: List, Next: Search, Up: Source
+
+Printing source lines
+=====================
+
+ To print lines from a source file, use the `list' command
+(abbreviated `l'). There are several ways to specify what part of the
+file you want to print.
+
+ Here are the forms of the `list' command most commonly used:
+
+`list LINENUM'
+ Print lines centered around line number LINENUM in the current
+ source file.
+
+`list FUNCTION'
+ Print lines centered around the beginning of function FUNCTION.
+
+`list'
+ Print more lines. If the last lines printed were printed with a
+ `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 (*note Examining the
+ Stack: Stack.), this prints lines centered around that line.
+
+`list -'
+ Print lines just before the lines last printed.
+
+ By default, GDB prints ten source lines with any of these forms of
+the `list' command. You can change this using `set listsize':
+
+`set listsize COUNT'
+ Make the `list' command display COUNT source lines (unless the
+ `list' argument explicitly specifies some other number).
+
+`show listsize'
+ Display the number of lines that `list' will currently display by
+ default.
+
+ Repeating a `list' command with RET discards the argument, so it is
+equivalent to typing just `list'. This is more useful than listing the
+same lines again. An exception is made for an argument of `-'; that
+argument is preserved in repetition so that each repetition moves up in
+the source file.
+
+ In general, the `list' command expects you to supply zero, one or two
+"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 `list':
+
+`list LINESPEC'
+ Print lines centered around the line specified by LINESPEC.
+
+`list FIRST,LAST'
+ Print lines from FIRST to LAST. Both arguments are linespecs.
+
+`list ,LAST'
+ Print lines ending with LAST.
+
+`list FIRST,'
+ Print lines starting with FIRST.
+
+`list +'
+ Print lines just after the lines last printed.
+
+`list -'
+ Print lines just before the lines last printed.
+
+`list'
+ As described in the preceding table.
+
+ Here are the ways of specifying a single source line--all the kinds
+of linespec.
+
+`NUMBER'
+ Specifies line NUMBER of the current source file. When a `list'
+ command has two linespecs, this refers to the same source file as
+ the first linespec.
+
+`+OFFSET'
+ Specifies the line OFFSET lines after the last line printed. When
+ used as the second linespec in a `list' command that has two, this
+ specifies the line OFFSET lines down from the first linespec.
+
+`-OFFSET'
+ Specifies the line OFFSET lines before the last line printed.
+
+`FILENAME:NUMBER'
+ Specifies line NUMBER in the source file FILENAME.
+
+`FUNCTION'
+ Specifies the line of the open-brace that begins the body of the
+ function FUNCTION.
+
+`FILENAME:FUNCTION'
+ Specifies the line of the open-brace that begins the body of the
+ function FUNCTION in the file FILENAME. You only need the file
+ name with a function name to avoid ambiguity when there are
+ identically named functions in different source files.
+
+`*ADDRESS'
+ Specifies the line containing the program address ADDRESS.
+ ADDRESS may be any expression.
+
+
+File: gdb.info, Node: Search, Next: Source Path, Prev: List, Up: Source
+
+Searching source files
+======================
+
+ There are two commands for searching through the current source file
+for a regular expression.
+
+`forward-search REGEXP'
+`search REGEXP'
+ The command `forward-search REGEXP' checks each line, starting
+ with the one following the last line listed, for a match for
+ REGEXP. It lists the line that is found. You can use synonym
+ `search REGEXP' or abbreviate the command name as `fo'.
+
+`reverse-search REGEXP'
+ The command `reverse-search REGEXP' checks each line, starting
+ with the one before the last line listed and going backward, for a
+ match for REGEXP. It lists the line that is found. You can
+ abbreviate this command as `rev'.
+
+
+File: gdb.info, Node: Source Path, Next: Machine Code, Prev: Search, Up: Source
+
+Specifying source directories
+=============================
+
+ 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. GDB has a list of directories to search for
+source files; this is called the "source path". Each time GDB 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 *not* used for this
+purpose. Neither is the current working directory, unless it happens
+to be in the source path.
+
+ If GDB cannot find a source file in the source path, and the object
+program records a directory, GDB tries that directory too. If the
+source path is empty, and there is no record of the compilation
+directory, GDB will, as a last resort, look in the current directory.
+
+ Whenever you reset or rearrange the source path, GDB will clear out
+any information it has cached about where source files are found, where
+each line is in the file, etc.
+
+ When you start GDB, its source path is empty. To add other
+directories, use the `directory' command.
+
+`directory DIRNAME ...'
+ Add directory DIRNAME to the front of the source path. Several
+ directory names may be given to this command, separated by `:' or
+ whitespace. You may specify a directory that is already in the
+ source path; this moves it forward, so it will be searched sooner.
+
+ You can use the string `$cdir' to refer to the compilation
+ directory (if one is recorded), and `$cwd' to refer to the current
+ working directory. `$cwd' is not the same as `.'--the former
+ tracks the current working directory as it changes during your GDB
+ session, while the latter is immediately expanded to the current
+ directory at the time you add an entry to the source path.
+
+`directory'
+ Reset the source path to empty again. This requires confirmation.
+
+`show directories'
+ Print the source path: show which directories it contains.
+
+ If your source path is cluttered with directories that are no longer
+of interest, GDB may sometimes cause confusion by finding the wrong
+versions of source. You can correct the situation as follows:
+
+ 1. Use `directory' with no argument to reset the source path to empty.
+
+ 2. Use `directory' with suitable arguments to reinstall the
+ directories you want in the source path. You can add all the
+ directories in one command.
+
+
+File: gdb.info, Node: Machine Code, Prev: Source Path, Up: Source
+
+Source and machine code
+=======================
+
+ You can use the command `info line' to map source lines to program
+addresses (and vice versa), and the command `disassemble' to display a
+range of addresses as machine instructions.
+
+`info line LINESPEC'
+ Print the starting and ending addresses of the compiled code for
+ source line LINESPEC. You can specify source lines in any of the
+ ways understood by the `list' command (*note Printing source
+ lines: List.).
+
+ For example, we can use `info line' to discover the location of the
+object code for the first line of function `m4_changequote':
+
+ (gdb) info line m4_changecom
+ Line 895 of "builtin.c" starts at pc 0x634c and ends at 0x6350.
+
+We can also inquire (using `*ADDR' as the form for LINESPEC) what
+source line covers a particular address:
+ (gdb) info line *0x63ff
+ Line 926 of "builtin.c" starts at pc 0x63e4 and ends at 0x6404.
+
+ After `info line', the default address for the `x' command is
+changed to the starting address of the line, so that `x/i' is
+sufficient to begin examining the machine code (*note Examining memory:
+Memory.). Also, this address is saved as the value of the convenience
+variable `$_' (*note Convenience variables: Convenience Vars.).
+
+`disassemble'
+ 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; the function
+ surrounding this value will be dumped. Two arguments specify a
+ range of addresses (first inclusive, second exclusive) to dump.
+
+ We can use `disassemble' to inspect the object code range shown in
+the last `info line' example (the example shows SPARC machine
+instructions):
+
+ (gdb) 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.
+
+
+File: gdb.info, Node: Data, Next: Languages, Prev: Source, Up: Top
+
+Examining Data
+**************
+
+ The usual way to examine data in your program is with the `print'
+command (abbreviated `p'), or its synonym `inspect'. It evaluates and
+prints the value of an expression of the language your program is
+written in (*note Using GDB with Different Languages: Languages.).
+
+`print EXP'
+`print /F EXP'
+ EXP is an expression (in the source language). By default the
+ value of EXP is printed in a format appropriate to its data type;
+ you can choose a different format by specifying `/F', where F is a
+ letter specifying the format; *note Output formats: Output
+ Formats..
+
+`print'
+`print /F'
+ If you omit EXP, GDB displays the last value again (from the
+ "value history"; *note Value history: Value History.). This
+ allows you to conveniently inspect the same value in an
+ alternative format.
+
+ A more low-level way of examining data is with the `x' command. It
+examines data in memory at a specified address and prints it in a
+specified format. *Note Examining memory: Memory.
+
+ If you are interested in information about types, or about how the
+fields of a struct or class are declared, use the `ptype EXP' command
+rather than `print'. *Note Examining the Symbol Table: Symbols.
+
+* 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
+
+* Floating Point Hardware:: Floating point hardware
+
+
+File: gdb.info, Node: Expressions, Next: Variables, Up: Data
+
+Expressions
+===========
+
+ `print' and many other GDB 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 GDB.
+This includes conditional expressions, function calls, casts and string
+constants. It unfortunately does not include symbols defined by
+preprocessor `#define' commands.
+
+ Because C is so widespread, most of the expressions shown in
+examples in this manual are in C. *Note Using GDB with Different
+Languages: Languages, for information on how to use expressions in other
+languages.
+
+ In this section, we discuss operators that you can use in GDB
+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.
+
+ GDB supports these operators in addition to those of programming
+languages:
+
+`@'
+ `@' is a binary operator for treating parts of memory as arrays.
+ *Note Artificial arrays: Arrays, for more information.
+
+`::'
+ `::' allows you to specify a variable in terms of the file or
+ function where it is defined. *Note Program variables: Variables.
+
+`{TYPE} ADDR'
+ Refers to an object of type TYPE stored at address ADDR in memory.
+ 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 ADDR.
+
+
+File: gdb.info, Node: Variables, Next: Arrays, Prev: Expressions, Up: Data
+
+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
+(*note Selecting a frame: Selection.); 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
+
+ foo (a)
+ int a;
+ {
+ bar (a);
+ {
+ int b = test ();
+ bar (b);
+ }
+ }
+
+you can examine and use the variable `a' whenever your program is
+executing within the function `foo', but you can only use or examine
+the variable `b' while your program is executing inside the block where
+`b' is declared.
+
+ 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:
+
+ FILE::VARIABLE
+ FUNCTION::VARIABLE
+
+Here FILE or FUNCTION is the name of the context for the static
+VARIABLE. In the case of file names, you can use quotes to make sure
+GDB parses the file name as a single word--for example, to print a
+global value of `x' defined in `f2.c':
+
+ (gdb) p 'f2.c'::x
+
+ This use of `::' is very rarely in conflict with the very similar
+use of the same notation in C++. GDB also supports use of the C++
+scope resolution operator in GDB expressions.
+
+ *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.
+ 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.
+
+
+File: gdb.info, Node: Arrays, Next: Output Formats, Prev: Variables, Up: Data
+
+Artificial arrays
+=================
+
+ 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
+"artificial array", using the binary operator `@'. The left operand of
+`@' 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
+
+ int *array = (int *) malloc (len * sizeof (int));
+
+you can print the contents of `array' with
+
+ p *array@len
+
+ The left operand of `@' must reside in memory. Array values made
+with `@' 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
+(*note 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 (*note Convenience variables: Convenience
+Vars.) as a counter in an expression that prints the first interesting
+value, and then repeat that expression via RET. For instance, suppose
+you have an array `dtab' of pointers to structures, and you are
+interested in the values of a field `fv' in each structure. Here is an
+example of what you might type:
+
+ set $i = 0
+ p dtab[$i++]->fv
+ RET
+ RET
+ ...
+
+
+File: gdb.info, Node: Output Formats, Next: Memory, Prev: Arrays, Up: Data
+
+Output formats
+==============
+
+ By default, GDB 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 "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
+`print' command with a slash and a format letter. The format letters
+supported are:
+
+`x'
+ Regard the bits of the value as an integer, and print the integer
+ in hexadecimal.
+
+`d'
+ Print as integer in signed decimal.
+
+`u'
+ Print as integer in unsigned decimal.
+
+`o'
+ Print as integer in octal.
+
+`t'
+ Print as integer in binary. The letter `t' stands for "two". (1)
+
+`a'
+ Print as an address, both absolute in hex and as an offset from the
+ nearest preceding symbol. This format can be used to discover
+ where (in what function) an unknown address is located:
+
+ (gdb) p/a 0x54320
+ $3 = 0x54320 <_initialize_vx+396>
+
+`c'
+ Regard as an integer and print it as a character constant.
+
+`f'
+ Regard the bits of the value as a floating point number and print
+ using typical floating point syntax.
+
+ For example, to print the program counter in hex (*note
+Registers::.), type
+
+ p/x $pc
+
+Note that no space is required before the slash; this is because command
+names in GDB cannot contain a slash.
+
+ To reprint the last value in the value history with a different
+format, you can use the `print' command with just a format and no
+expression. For example, `p/x' reprints the last value in hex.
+
+ ---------- Footnotes ----------
+
+ (1) `b' cannot be used because these format letters are also used
+with the `x' command, where `b' stands for "byte"; *note Examining
+memory: Memory..
+
+
+File: gdb.info, Node: Memory, Next: Auto Display, Prev: Output Formats, Up: Data
+
+Examining memory
+================
+
+ You can use the command `x' (for "examine") to examine memory in any
+of several formats, independently of your program's data types.
+
+`x/NFU ADDR'
+`x ADDR'
+`x'
+ Use the `x' command to examine memory.
+
+ N, F, and U are all optional parameters that specify how much memory
+to display and how to format it; ADDR is an expression giving the
+address where you want to start displaying memory. If you use defaults
+for NFU, you need not type the slash `/'. Several commands set
+convenient defaults for ADDR.
+
+N, the repeat count
+ The repeat count is a decimal integer; the default is 1. It
+ specifies how much memory (counting by units U) to display.
+
+F, the display format
+ The display format is one of the formats used by `print', or `s'
+ (null-terminated string) or `i' (machine instruction). The
+ default is `x' (hexadecimal) initially, or the format from the
+ last time you used either `x' or `print'.
+
+U, the unit size
+ The unit size is any of
+
+ `b'
+ Bytes.
+
+ `h'
+ Halfwords (two bytes).
+
+ `w'
+ Words (four bytes). This is the initial default.
+
+ `g'
+ Giant words (eight bytes).
+
+ Each time you specify a unit size with `x', that size becomes the
+ default unit the next time you use `x'. (For the `s' and `i'
+ formats, the unit size is ignored and is normally not written.)
+
+ADDR, starting display address
+ ADDR is the address where you want GDB 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.
+ *Note Expressions: Expressions, for more information on
+ expressions. The default for ADDR is usually just after the last
+ address examined--but several other commands also set the default
+ address: `info breakpoints' (to the address of the last breakpoint
+ listed), `info line' (to the starting address of a line), and
+ `print' (if you use it to display a value from memory).
+
+ For example, `x/3uh 0x54320' is a request to display three halfwords
+(`h') of memory, formatted as unsigned decimal integers (`u'), starting
+at address `0x54320'. `x/4xw $sp' prints the four words (`w') of
+memory above the stack pointer (here, `$sp'; *note Registers::.) in
+hexadecimal (`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 will work. The output
+specifications `4xw' and `4wx' mean exactly the same thing. (However,
+the count N must come first; `wx4' will not work.)
+
+ Even though the unit size U is ignored for the formats `s' and `i',
+you might still want to use a count N; for example, `3i' specifies that
+you want to see three machine instructions, including any operands.
+The command `disassemble' gives an alternative way of inspecting
+machine instructions; *note Source and machine code: Machine Code..
+
+ All the defaults for the arguments to `x' are designed to make it
+easy to continue scanning memory with minimal specifications each time
+you use `x'. For example, after you have inspected three machine
+instructions with `x/3i ADDR', you can inspect the next seven with just
+`x/7'. If you use RET to repeat the `x' command, the repeat count N is
+used again; the other arguments default as for successive uses of `x'.
+
+ The addresses and contents printed by the `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, GDB makes these values available for
+subsequent use in expressions as values of the convenience variables
+`$_' and `$__'. After an `x' command, the last address examined is
+available for use in expressions in the convenience variable `$_'. The
+contents of that address, as examined, are available in the convenience
+variable `$__'.
+
+ If the `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.
+
+
+File: gdb.info, Node: Auto Display, Next: Print Settings, Prev: Memory, Up: Data
+
+Automatic display
+=================
+
+ 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
+"automatic display list" so that GDB will print 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:
+
+ 2: foo = 38
+ 3: bar[5] = (struct hack *) 0x3804
+
+This display shows item numbers, expressions and their current values.
+As with displays you request manually using `x' or `print', you can
+specify the output format you prefer; in fact, `display' decides
+whether to use `print' or `x' depending on how elaborate your format
+specification is--it uses `x' if you specify a unit size, or one of the
+two formats (`i' and `s') that are only supported by `x'; otherwise it
+uses `print'.
+
+`display EXP'
+ Add the expression EXP to the list of expressions to display each
+ time your program stops. *Note Expressions: Expressions.
+
+ `display' will not repeat if you press RET again after using it.
+
+`display/FMT EXP'
+ For FMT specifying only a display format and not a size or count,
+ add the expression EXP to the auto-display list but arrange to
+ display it each time in the specified format FMT. *Note Output
+ formats: Output Formats.
+
+`display/FMT ADDR'
+ For FMT `i' or `s', or including a unit-size or a number of units,
+ add the expression ADDR as a memory address to be examined each
+ time your program stops. Examining means in effect doing `x/FMT
+ ADDR'. *Note Examining memory: Memory.
+
+ For example, `display/i $pc' can be helpful, to see the machine
+instruction about to be executed each time execution stops (`$pc' is a
+common name for the program counter; *note Registers::.).
+
+`undisplay DNUMS...'
+`delete display DNUMS...'
+ Remove item numbers DNUMS from the list of expressions to display.
+
+ `undisplay' will not repeat if you press RET after using it.
+ (Otherwise you would just get the error `No display number ...'.)
+
+`disable display DNUMS...'
+ Disable the display of item numbers DNUMS. A disabled display
+ item is not printed automatically, but is not forgotten. It may be
+ enabled again later.
+
+`enable display DNUMS...'
+ Enable display of item numbers DNUMS. It becomes effective once
+ again in auto display of its expression, until you specify
+ otherwise.
+
+`display'
+ Display the current values of the expressions on the list, just as
+ is done when your program stops.
+
+`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.
+
+ 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
+`display last_char' while inside a function with an argument
+`last_char', then this argument will be displayed while your program
+continues to stop inside that function. When it stops elsewhere--where
+there is no variable `last_char'--display is disabled. The next time
+your program stops where `last_char' is meaningful, you can enable the
+display expression once again.
+
+
+File: gdb.info, Node: Print Settings, Next: Value History, Prev: Auto Display, Up: Data
+
+Print settings
+==============
+
+ GDB provides the following ways to control how arrays, structures,
+and symbols are printed.
+
+These settings are useful for debugging programs in any language:
+
+`set print address'
+`set print address on'
+ GDB will print 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 on. For example, this is what a stack frame
+ display looks like, with `set print address on':
+
+ (gdb) f
+ #0 set_quotes (lq=0x34c78 "<<", rq=0x34c88 ">>")
+ at input.c:530
+ 530 if (lquote != def_lquote)
+
+`set print address off'
+ Do not print addresses when displaying their contents. For
+ example, this is the same stack frame displayed with `set print
+ address off':
+
+ (gdb) set print addr off
+ (gdb) f
+ #0 set_quotes (lq="<<", rq=">>") at input.c:530
+ 530 if (lquote != def_lquote)
+
+ You can use `set print address off' to eliminate all machine
+ dependent displays from the GDB interface. For example, with
+ `print address off', you should get the same text for backtraces on
+ all machines--whether or not they involve pointer arguments.
+
+`show print address'
+ Show whether or not addresses are to be printed.
+
+ When GDB 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
+`info line', for example `info line *0x4537'. Alternately, you can set
+GDB to print the source file and line number when it prints a symbolic
+address:
+
+`set print symbol-filename on'
+ Tell GDB to print the source file name and line number of a symbol
+ in the symbolic form of an address.
+
+`set print symbol-filename off'
+ Do not print source file name and line number of a symbol. This
+ is the default.
+
+`show print symbol-filename'
+ Show whether or not GDB will print the source file name and line
+ number of a symbol in the symbolic form of an address.
+
+ Also, you may wish to see the symbolic form only if the address being
+printed is reasonably close to the closest earlier symbol:
+
+`set print max-symbolic-offset MAX-OFFSET'
+ Tell GDB to only display the symbolic form of an address if the
+ offset between the closest earlier symbol and the address is less
+ than MAX-OFFSET. The default is 0, which means to always print the
+ symbolic form of an address, if any symbol precedes it.
+
+`show print max-symbolic-offset'
+ Ask how large the maximum offset is that GDB will print in a
+ symbolic address.
+
+`set print array'
+`set print array on'
+ GDB will pretty-print arrays. This format is more convenient to
+ read, but uses more space. The default is off.
+
+`set print array off'
+ Return to compressed format for arrays.
+
+`show print array'
+ Show whether compressed or pretty format is selected for displaying
+ arrays.
+
+`set print elements NUMBER-OF-ELEMENTS'
+ If GDB is printing a large array, it will stop printing after it
+ has printed the number of elements set by the `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.
+
+`show print elements'
+ Display the number of elements of a large array that GDB will print
+ before losing patience.
+
+`set print pretty on'
+ Cause GDB to print structures in an indented format with one
+ member per line, like this:
+
+ $1 = {
+ next = 0x0,
+ flags = {
+ sweet = 1,
+ sour = 1
+ },
+ meat = 0x54 "Pork"
+ }
+
+`set print pretty off'
+ Cause GDB to print structures in a compact format, like this:
+
+ $1 = {next = 0x0, flags = {sweet = 1, sour = 1}, \
+ meat = 0x54 "Pork"}
+
+ This is the default format.
+
+`show print pretty'
+ Show which format GDB will use to print structures.
+
+`set print sevenbit-strings on'
+ Print using only seven-bit characters; if this option is set, GDB
+ will display any eight-bit characters (in strings or character
+ values) using the notation `\'NNN. For example, `M-a' is
+ displayed as `\341'.
+
+`set print sevenbit-strings off'
+ Print using either seven-bit or eight-bit characters, as required.
+ This is the default.
+
+`show print sevenbit-strings'
+ Show whether or not GDB will print only seven-bit characters.
+
+`set print union on'
+ Tell GDB to print unions which are contained in structures. This
+ is the default setting.
+
+`set print union off'
+ Tell GDB not to print unions which are contained in structures.
+
+`show print union'
+ Ask GDB whether or not it will print unions which are contained in
+ structures.
+
+ For example, given the declarations
+
+ 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}};
+
+ with `set print union on' in effect `p foo' would print
+
+ $1 = {it = Tree, form = {tree = Acorn, bug = Cocoon}}
+
+ and with `set print union off' in effect it would print
+
+ $1 = {it = Tree, form = {...}}
+
+These settings are of interest when debugging C++ programs:
+
+`set print demangle'
+`set print demangle on'
+ 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 `on'.
+
+`show print demangle'
+ Show whether C++ names will be printed in mangled or demangled
+ form.
+
+`set print asm-demangle'
+`set print asm-demangle on'
+ 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.
+
+`show print asm-demangle'
+ Show whether C++ names in assembly listings will be printed in
+ mangled or demangled form.
+
+`set demangle-style STYLE'
+ Choose among several encoding schemes used by different compilers
+ to represent C++ names. The choices for STYLE are currently:
+
+ `auto'
+ Allow GDB to choose a decoding style by inspecting your
+ program.
+
+ `gnu'
+ Decode based on the GNU C++ compiler (`g++') encoding
+ algorithm.
+
+ `lucid'
+ Decode based on the Lucid C++ compiler (`lcc') encoding
+ algorithm.
+
+ `arm'
+ Decode using the algorithm in the `C++ Annotated Reference
+ Manual'. *Warning:* this setting alone is not sufficient to
+ allow debugging `cfront'-generated executables. GDB would
+ require further enhancement to permit that.
+
+`show demangle-style'
+ Display the encoding style currently in use for decoding C++
+ symbols.
+
+`set print object'
+`set print object on'
+ When displaying a pointer to an object, identify the *actual*
+ (derived) type of the object rather than the *declared* type, using
+ the virtual function table.
+
+`set print object off'
+ Display only the declared type of objects, without reference to the
+ virtual function table. This is the default setting.
+
+`show print object'
+ Show whether actual, or declared, object types will be displayed.
+
+`set print vtbl'
+`set print vtbl on'
+ Pretty print C++ virtual function tables. The default is off.
+
+`set print vtbl off'
+ Do not pretty print C++ virtual function tables.
+
+`show print vtbl'
+ Show whether C++ virtual function tables are pretty printed, or
+ not.
+
+
+File: gdb.info, Node: Value History, Next: Convenience Vars, Prev: Print Settings, Up: Data
+
+Value history
+=============
+
+ Values printed by the `print' command are saved in the GDB "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 `file' or `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.
+
+ The values printed are given "history numbers" by which you can
+refer to them. These are successive integers starting with one.
+`print' shows you the history number assigned to a value by printing
+`$NUM = ' before the value; here NUM is the history number.
+
+ To refer to any previous value, use `$' followed by the value's
+history number. The way `print' labels its output is designed to
+remind you of this. Just `$' refers to the most recent value in the
+history, and `$$' refers to the value before that. `$$N' refers to the
+Nth value from the end; `$$2' is the value just prior to `$$', `$$1' is
+equivalent to `$$', and `$$0' is equivalent to `$'.
+
+ 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
+
+ p *$
+
+ If you have a chain of structures where the component `next' points
+to the next one, you can print the contents of the next one with this:
+
+ p *$.next
+
+You can print successive links in the chain by repeating this
+command--which you can do by just typing RET.
+
+ Note that the history records values, not expressions. If the value
+of `x' is 4 and you type these commands:
+
+ print x
+ set x=5
+
+then the value recorded in the value history by the `print' command
+remains 4 even though the value of `x' has changed.
+
+`show values'
+ Print the last ten values in the value history, with their item
+ numbers. This is like `p $$9' repeated ten times, except that
+ `show values' does not change the history.
+
+`show values N'
+ Print ten history values centered on history item number N.
+
+`show values +'
+ Print ten history values just after the values last printed. If
+ no more values are available, produces no display.
+
+ Pressing RET to repeat `show values N' has exactly the same effect
+as `show values +'.
+
+
+File: gdb.info, Node: Convenience Vars, Next: Registers, Prev: Value History, Up: Data
+
+Convenience variables
+=====================
+
+ GDB provides "convenience variables" that you can use within GDB to
+hold on to a value and refer to it later. These variables exist
+entirely within GDB; 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 `$'. Any name preceded by
+`$' can be used for a convenience variable, unless it is one of the
+predefined machine-specific register names (*note Registers::.).
+(Value history references, in contrast, are *numbers* preceded by `$'.
+*Note 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:
+
+ set $foo = *object_ptr
+
+would save in `$foo' the value contained in the object pointed to by
+`object_ptr'.
+
+ Using a convenience variable for the first time creates it, but its
+value is `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.
+
+`show convenience'
+ Print a list of convenience variables used so far, and their
+ values. Abbreviated `show con'.
+
+ 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:
+
+ set $i = 0
+ print bar[$i++]->contents
+ ... repeat that command by typing RET.
+
+ Some convenience variables are created automatically by GDB and given
+values likely to be useful.
+
+`$_'
+ The variable `$_' is automatically set by the `x' command to the
+ last address examined (*note Examining memory: Memory.). Other
+ commands which provide a default address for `x' to examine also
+ set `$_' to that address; these commands include `info line' and
+ `info breakpoint'. The type of `$_' is `void *' except when set
+ by the `x' command, in which case it is a pointer to the type of
+ `$__'.
+
+`$__'
+ The variable `$__' is automatically set by the `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.
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-4 b/gnu/usr.bin/gdb/doc/gdb.info-4
new file mode 100644
index 0000000..b0758fa
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-4
@@ -0,0 +1,1349 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ 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.
+
+ 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.
+
+
+File: gdb.info, Node: Registers, Next: Floating Point Hardware, Prev: Convenience Vars, Up: Data
+
+Registers
+=========
+
+ You can refer to machine register contents, in expressions, as
+variables with names starting with `$'. The names of registers are
+different for each machine; use `info registers' to see the names used
+on your machine.
+
+`info registers'
+ Print the names and values of all registers except floating-point
+ registers (in the selected stack frame).
+
+`info all-registers'
+ Print the names and values of all registers, including
+ floating-point registers.
+
+`info registers REGNAME ...'
+ Print the relativized value of each specified register REGNAME.
+ rEGNAME may be any register name valid on the machine you are
+ using, with or without the initial `$'.
+
+ GDB 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
+`$pc' and `$sp' are used for the program counter register and the stack
+pointer. `$fp' is used for a register that contains a pointer to the
+current stack frame, and `$ps' is used for a register that contains the
+processor status. For example, you could print the program counter in
+hex with
+
+ p/x $pc
+
+or print the instruction to be executed next with
+
+ x/i $pc
+
+or add four to the stack pointer(1) with
+
+ set $sp += 4
+
+ 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 `info registers'
+command shows the canonical names. For example, on the SPARC, `info
+registers' displays the processor status register as `$psr' but you can
+also refer to it as `$ps'.
+
+ GDB 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 *print* it as a floating point value with `print/f
+$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,
+GDB normally works with the virtual format only (the format that makes
+sense for your program), but the `info registers' command prints the
+data in both formats.
+
+ Normally, register values are relative to the selected stack frame
+(*note Selecting a frame: Selection.). 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 `frame 0').
+
+ However, GDB must deduce where registers are saved, from the machine
+code generated by your compiler. If some registers are not saved, or if
+GDB is unable to locate the saved registers, the selected stack frame
+will make no difference.
+
+`set rstack_high_address ADDRESS'
+ On AMD 29000 family processors, registers are saved in a separate
+ "register stack". There is no way for GDB to determine the extent
+ of this stack. Normally, GDB just assumes that the stack is "large
+ enough". This may result in GDB 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 `set
+ rstack_high_address' command. The argument should be an address,
+ which you will probably want to precede with `0x' to specify in
+ hexadecimal.
+
+`show rstack_high_address'
+ Display the current limit of the register stack, on AMD 29000
+ family processors.
+
+ ---------- Footnotes ----------
+
+ (1) 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 `$sp' is
+not allowed when other stack frames are selected. To pop entire frames
+off the stack, regardless of machine architecture, use `return'; *note
+Returning from a function: Returning..
+
+
+File: gdb.info, Node: Floating Point Hardware, Prev: Registers, Up: Data
+
+Floating point hardware
+=======================
+
+ Depending on the host machine architecture, GDB may be able to give
+you more information about the status of the floating point hardware.
+
+`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, `info float' is not
+ available at all.
+
+
+File: gdb.info, Node: Languages, Next: Symbols, Prev: Data, Up: Top
+
+Using GDB with Different Languages
+**********************************
+
+ Although programming languages generally have common aspects, they
+are rarely expressed in the same manner. For instance, in ANSI C,
+dereferencing a pointer `p' is accomplished by `*p', but in Modula-2,
+it is accomplished by `p^'. Values can also be represented (and
+displayed) differently. Hex numbers in C are written like `0x1ae',
+while in Modula-2 they appear as `1AEH'.
+
+ Language-specific information is built into GDB for some languages,
+allowing you to express operations like the above in your program's
+native language, and allowing GDB 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 "working language",
+can be selected manually, or GDB can set it automatically.
+
+* Menu:
+
+* Setting:: Switching between source languages
+* Show:: Displaying the language
+
+* Checks:: Type and range checks
+
+* Support:: Supported languages
+
+
+File: gdb.info, Node: Setting, Next: Show, Up: Languages
+
+Switching between source languages
+==================================
+
+ There are two ways to control the working language--either have GDB
+set it automatically, or select it manually yourself. You can use the
+`set language' command for either purpose. On startup, GDB defaults to
+setting the language automatically.
+
+* Menu:
+
+* Manually:: Setting the working language manually
+* Automatically:: Having GDB infer the source language
+
+
+File: gdb.info, Node: Manually, Next: Automatically, Up: Setting
+
+Setting the working language
+----------------------------
+
+ If you allow GDB to set the language automatically, expressions are
+interpreted the same way in your debugging session and your program.
+
+ If you wish, you may set the language manually. To do this, issue
+the command `set language LANG', where LANG is the name of a language,
+such as `c' or `modula-2'. For a list of the supported languages, type
+`set language'.
+
+ Setting the language manually prevents GDB 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 GDB was parsing Modula-2, a command such as:
+
+ print a = b + c
+
+might not have the effect you intended. In C, this means to add `b'
+and `c' and place the result in `a'. The result printed would be the
+value of `a'. In Modula-2, this means to compare `a' to the result of
+`b+c', yielding a `BOOLEAN' value.
+
+
+File: gdb.info, Node: Automatically, Prev: Manually, Up: Setting
+
+Having GDB infer the source language
+------------------------------------
+
+ To have GDB set the working language automatically, use `set
+language local' or `set language auto'. GDB then infers the language
+that a program was written in by looking at the name of its source
+files, and examining their extensions:
+
+`*.mod'
+ Modula-2 source file
+
+`*.c'
+ C source file
+
+`*.C'
+`*.cc'
+ C++ source file
+
+ 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), GDB 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 GDB 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 `set language auto' in this case
+frees you from having to set the working language manually.
+
+
+File: gdb.info, Node: Show, Next: Checks, Prev: Setting, Up: Languages
+
+Displaying the language
+=======================
+
+ The following commands will help you find out which language is the
+working language, and also what language source files were written in.
+
+`show language'
+ Display the current working language. This is the language you
+ can use with commands such as `print' to build and compute
+ expressions that may involve variables in your program.
+
+`info frame'
+ Among the other information listed here (*note Information about a
+ frame: Frame Info.) is the source language for this frame. This
+ is the language that will become the working language if you ever
+ use an identifier that is in this frame.
+
+`info source'
+ Among the other information listed here (*note Examining the
+ Symbol Table: Symbols.) is the source language of this source file.
+
+
+File: gdb.info, Node: Checks, Next: Support, Prev: Show, Up: Languages
+
+Type and range checking
+=======================
+
+ *Warning:* In this release, the GDB commands for type and range
+ checking are included, but they do not yet have any effect. This
+ section documents the intended facilities.
+
+ 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.
+
+ GDB can check for conditions like the above if you wish. Although
+GDB will not check the statements in your program, it can check
+expressions entered directly into GDB for evaluation via the `print'
+command, for example. As with the working language, GDB can also
+decide whether or not to check automatically based on your program's
+source language. *Note Supported languages: Support, for the default
+settings of supported languages.
+
+* Menu:
+
+* Type Checking:: An overview of type checking
+* Range Checking:: An overview of range checking
+
+
+File: gdb.info, Node: Type Checking, Next: Range Checking, Up: Checks
+
+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,
+
+ 1 + 2 => 3
+but
+ error--> 1 + 2.3
+
+ The second example fails because the `CARDINAL' 1 is not
+type-compatible with the `REAL' 2.3.
+
+ For expressions you use in GDB commands, you can tell the GDB 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, GDB
+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 GDB from evaluating an expression. For instance, GDB does
+not know how to add an `int' and a `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. *Note Supported languages: Support, for further details on
+specific languages.
+
+ GDB provides some additional commands for controlling the type
+checker:
+
+`set check type auto'
+ Set type checking on or off based on the current working language.
+ *Note Supported languages: Support, for the default settings for
+ each language.
+
+`set check type on'
+`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, GDB prints a
+ message and aborts evaluation of the expression.
+
+`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, GDB cannot add numbers
+ and structures.
+
+`show type'
+ Show the current setting of the type checker, and whether or not
+ GDB is setting it automatically.
+
+
+File: gdb.info, Node: Range Checking, Prev: Type Checking, Up: Checks
+
+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 GDB commands, you can tell GDB 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 M is the largest
+integer value, and S is the smallest, then
+
+ M + 1 => S
+
+ This, too, is specific to individual languages, and in some cases
+specific to individual compilers or machines. *Note Supported
+languages: Support, for further details on specific languages.
+
+ GDB provides some additional commands for controlling the range
+checker:
+
+`set check range auto'
+ Set range checking on or off based on the current working language.
+ *Note Supported languages: Support, for the default settings for
+ each language.
+
+`set check range on'
+`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.
+
+`set check range warn'
+ Output messages when the GDB 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).
+
+`show range'
+ Show the current setting of the range checker, and whether or not
+ it is being set automatically by GDB.
+
+
+File: gdb.info, Node: Support, Prev: Checks, Up: Languages
+
+Supported languages
+===================
+
+ GDB 4 supports C, C++, and Modula-2. Some GDB features may be used
+in expressions regardless of the language you use: the GDB `@' and `::'
+operators, and the `{type}addr' construct (*note 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 GDB. These sections are not meant to be language
+tutorials or references, but serve only as a reference guide to what the
+GDB expression parser will accept, 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.
+
+* Menu:
+
+* C:: C and C++
+* Modula-2:: Modula-2
+
+
+File: gdb.info, Node: C, Next: Modula-2, Up: Support
+
+C and C++
+---------
+
+ Since C and C++ are so closely related, many features of GDB apply
+to both languages. Whenever this is the case, we discuss both languages
+together.
+
+ The C++ debugging facilities are jointly implemented by the GNU C++
+compiler and GDB. Therefore, to debug your C++ code effectively, you
+must compile your C++ programs with the GNU C++ compiler, `g++'.
+
+* 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++
+
+* C Checks:: C and C++ type and range checks
+
+* Debugging C:: GDB and C
+* Debugging C plus plus:: Special features for C++
+
+
+File: gdb.info, Node: C Operators, Next: C Constants, Up: C
+
+C and C++ operators
+-------------------
+
+ Operators must be defined on values of specific types. For instance,
+`+' is defined on numbers, but not on structures. Operators are often
+defined on groups of types.
+
+ For the purposes of C and C++, the following definitions hold:
+
+ * *Integral types* include `int' with any of its storage-class
+ specifiers; `char'; and `enum'.
+
+ * *Floating-point types* include `float' and `double'.
+
+ * *Pointer types* include all types defined as `(TYPE *)'.
+
+ * *Scalar types* include all of the above.
+
+The following operators are supported. They are listed here in order
+of increasing precedence:
+
+`,'
+ 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.
+
+`='
+ Assignment. The value of an assignment expression is the value
+ assigned. Defined on scalar types.
+
+`OP='
+ Used in an expression of the form `A OP= B', and translated to
+ `A = A OP B'. `OP=' and `=' have the same precendence. OP is any
+ one of the operators `|', `^', `&', `<<', `>>', `+', `-', `*',
+ `/', `%'.
+
+`?:'
+ The ternary operator. `A ? B : C' can be thought of as: if A
+ then B else C. A should be of an integral type.
+
+`||'
+ Logical OR. Defined on integral types.
+
+`&&'
+ Logical AND. Defined on integral types.
+
+`|'
+ Bitwise OR. Defined on integral types.
+
+`^'
+ Bitwise exclusive-OR. Defined on integral types.
+
+`&'
+ Bitwise AND. Defined on integral types.
+
+`==, !='
+ Equality and inequality. Defined on scalar types. The value of
+ these expressions is 0 for false and non-zero for true.
+
+`<, >, <=, >='
+ 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.
+
+`<<, >>'
+ left shift, and right shift. Defined on integral types.
+
+`@'
+ The GDB "artificial array" operator (*note Expressions:
+ Expressions.).
+
+`+, -'
+ Addition and subtraction. Defined on integral types,
+ floating-point types and pointer types.
+
+`*, /, %'
+ Multiplication, division, and modulus. Multiplication and
+ division are defined on integral and floating-point types.
+ Modulus is defined on integral types.
+
+`++, --'
+ 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.
+
+`*'
+ Pointer dereferencing. Defined on pointer types. Same precedence
+ as `++'.
+
+`&'
+ Address operator. Defined on variables. Same precedence as `++'.
+
+ For debugging C++, GDB implements a use of `&' beyond what is
+ allowed in the C++ language itself: you can use `&(&REF)' (or, if
+ you prefer, simply `&&REF') to examine the address where a C++
+ reference variable (declared with `&REF') is stored.
+
+`-'
+ Negative. Defined on integral and floating-point types. Same
+ precedence as `++'.
+
+`!'
+ Logical negation. Defined on integral types. Same precedence as
+ `++'.
+
+`~'
+ Bitwise complement operator. Defined on integral types. Same
+ precedence as `++'.
+
+`., ->'
+ Structure member, and pointer-to-structure member. For
+ convenience, GDB regards the two as equivalent, choosing whether
+ to dereference a pointer based on the stored type information.
+ Defined on `struct' and `union' data.
+
+`[]'
+ Array indexing. `A[I]' is defined as `*(A+I)'. Same precedence
+ as `->'.
+
+`()'
+ Function parameter list. Same precedence as `->'.
+
+`::'
+ C++ scope resolution operator. Defined on `struct', `union', and
+ `class' types.
+
+`::'
+ Doubled colons also represent the GDB scope operator (*note
+ Expressions: Expressions.). Same precedence as `::', above.
+
+
+File: gdb.info, Node: C Constants, Next: Cplus expressions, Prev: C Operators, Up: C
+
+C and C++ constants
+-------------------
+
+ GDB allows you to express the constants of C and C++ in the
+following ways:
+
+ * Integer constants are a sequence of digits. Octal constants are
+ specified by a leading `0' (ie. zero), and hexadecimal constants by
+ a leading `0x' or `0X'. Constants may also end with a letter `l',
+ specifying that the constant should be treated as a `long' value.
+
+ * 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:
+ `e[[+]|-]NNN', where NNN is another sequence of digits. The `+'
+ is optional for positive exponents.
+
+ * Enumerated constants consist of enumerated identifiers, or their
+ integral equivalents.
+
+ * Character constants are a single character surrounded by single
+ quotes (`''), or a number--the ordinal value of the corresponding
+ character (usually its ASCII value). Within quotes, the single
+ character may be represented by a letter or by "escape sequences",
+ which are of the form `\NNN', where NNN is the octal representation
+ of the character's ordinal value; or of the form `\X', where `X'
+ is a predefined special character--for example, `\n' for newline.
+
+ * String constants are a sequence of character constants surrounded
+ by double quotes (`"').
+
+ * Pointer constants are an integral value. You can also write
+ pointers to constants using the C operator `&'.
+
+ * Array constants are comma-separated lists surrounded by braces `{'
+ and `}'; for example, `{1,2,3}' is a three-element array of
+ integers, `{{1,2}, {3,4}, {5,6}}' is a three-by-two array, and
+ `{&"hi", &"there", &"fred"}' is a three-element array of pointers.
+
+
+File: gdb.info, Node: Cplus expressions, Next: C Defaults, Prev: C Constants, Up: C
+
+C++ expressions
+---------------
+
+ GDB expression handling has a number of extensions to interpret a
+significant subset of C++ expressions.
+
+ *Warning:* Most of these extensions depend on the use of additional
+ debugging information in the symbol table, and thus require a rich,
+ extendable object code format. In particular, if your system uses
+ a.out, MIPS ECOFF, RS/6000 XCOFF, or Sun ELF with stabs extensions
+ to the symbol table, these facilities are all available. Where
+ the object code format is standard COFF, on the other hand, most
+ of the C++ support in GDB will *not* work, nor can it. For the
+ standard SVr4 debugging format, DWARF in ELF, the standard is
+ still evolving, so the C++ support in GDB is still fragile; when
+ this debugging format stabilizes, however, C++ support will also
+ be available on systems that use it.
+
+ 1. Member function calls are allowed; you can use expressions like
+
+ count = aml->GetOriginal(x, y)
+
+ 2. While a member function is active (in the selected stack frame),
+ your expressions have the same namespace available as the member
+ function; that is, GDB allows implicit references to the class
+ instance pointer `this' following the same rules as C++.
+
+ 3. You can call overloaded functions; GDB will resolve 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. GDB will not perform conversions requiring constructors or
+ user-defined type operators.
+
+ 4. GDB 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 GDB 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 *address* of a reference variable is always
+ shown, unless you have specified `set print address off'.
+
+ 5. GDB supports the C++ name resolution operator `::'--your
+ expressions can use it just as expressions in your program do.
+ Since one scope may be defined in another, you can use `::'
+ repeatedly if necessary, for example in an expression like
+ `SCOPE1::SCOPE2::NAME'. GDB also allows resolving name scope by
+ reference to source files, in both C and C++ debugging (*note
+ Program variables: Variables.).
+
+
+File: gdb.info, Node: C Defaults, Next: C Checks, Prev: Cplus expressions, Up: C
+
+C and C++ defaults
+------------------
+
+ If you allow GDB to set type and range checking automatically, they
+both default to `off' whenever the working language changes to C or
+C++. This happens regardless of whether you, or GDB, selected the
+working language.
+
+ If you allow GDB 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 `.c', `.C', or `.cc'. *Note Having GDB infer
+the source language: Automatically, for further details.
+
+
+File: gdb.info, Node: C Checks, Next: Debugging C, Prev: C Defaults, Up: C
+
+C and C++ type and range checks
+-------------------------------
+
+ By default, when GDB parses C or C++ expressions, type checking is
+not used. However, if you turn type checking on, GDB will consider two
+variables type equivalent if:
+
+ * The two variables are structured and have the same structure,
+ union, or enumerated tag.
+
+ * Two two variables have the same type name, or types that have been
+ declared equivalent through `typedef'.
+
+ 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.
+
+
+File: gdb.info, Node: Debugging C, Next: Debugging C plus plus, Prev: C Checks, Up: C
+
+GDB and C
+---------
+
+ The `set print union' and `show print union' commands apply to the
+`union' type. When set to `on', any `union' that is inside a `struct'
+or `class' will also be printed. Otherwise, it will appear as `{...}'.
+
+ The `@' operator aids in the debugging of dynamic arrays, formed
+with pointers and a memory allocation function. *Note Expressions:
+Expressions.
+
+
+File: gdb.info, Node: Debugging C plus plus, Prev: Debugging C, Up: C
+
+GDB features for C++
+--------------------
+
+ Some GDB commands are particularly useful with C++, and some are
+designed specifically for use with C++. Here is a summary:
+
+`breakpoint menus'
+ When you want a breakpoint in a function whose name is overloaded,
+ GDB breakpoint menus help you specify which function definition
+ you want. *Note Breakpoint menus: Breakpoint Menus.
+
+`rbreak REGEX'
+ Setting breakpoints using regular expressions is helpful for
+ setting breakpoints on overloaded functions that are not members
+ of any special classes. *Note Setting breakpoints: Set Breaks.
+
+`catch EXCEPTIONS'
+`info catch'
+ Debug C++ exception handling using these commands. *Note
+ Breakpoints and exceptions: Exception Handling.
+
+`ptype TYPENAME'
+ Print inheritance relationships as well as other information for
+ type TYPENAME. *Note Examining the Symbol Table: Symbols.
+
+`set print demangle'
+`show print demangle'
+`set print asm-demangle'
+`show print asm-demangle'
+ Control whether C++ symbols display in their source form, both when
+ displaying code as C++ source and when displaying disassemblies.
+ *Note Print settings: Print Settings.
+
+`set print object'
+`show print object'
+ Choose whether to print derived (actual) or declared types of
+ objects. *Note Print settings: Print Settings.
+
+`set print vtbl'
+`show print vtbl'
+ Control the format for printing virtual function tables. *Note
+ Print settings: Print Settings.
+
+`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 `SYMBOL(TYPES)' rather than just SYMBOL. You can also
+ use the GDB command-line word completion facilities to list the
+ available choices, or to finish the type list for you. *Note
+ Command completion: Completion, for details on how to do this.
+
+
+File: gdb.info, Node: Modula-2, Prev: C, Up: Support
+
+Modula-2
+--------
+
+ The extensions made to GDB 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 will most likely result in an error
+as GDB reads in the executable's symbol table.
+
+* 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 `::' and `.'
+* GDB/M2:: GDB and Modula-2
+
+
+File: gdb.info, Node: M2 Operators, Next: Built-In Func/Proc, Up: Modula-2
+
+Operators
+---------
+
+ Operators must be defined on values of specific types. For instance,
+`+' 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:
+
+ * *Integral types* consist of `INTEGER', `CARDINAL', and their
+ subranges.
+
+ * *Character types* consist of `CHAR' and its subranges.
+
+ * *Floating-point types* consist of `REAL'.
+
+ * *Pointer types* consist of anything declared as `POINTER TO TYPE'.
+
+ * *Scalar types* consist of all of the above.
+
+ * *Set types* consist of `SET' and `BITSET' types.
+
+ * *Boolean types* consist of `BOOLEAN'.
+
+The following operators are supported, and appear in order of
+increasing precedence:
+
+`,'
+ Function argument or array index separator.
+
+`:='
+ Assignment. The value of VAR `:=' VALUE is VALUE.
+
+`<, >'
+ Less than, greater than on integral, floating-point, or enumerated
+ types.
+
+`<=, >='
+ 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 `<'.
+
+`=, <>, #'
+ Equality and two ways of expressing inequality, valid on scalar
+ types. Same precedence as `<'. In GDB scripts, only `<>' is
+ available for inequality, since `#' conflicts with the script
+ comment character.
+
+`IN'
+ Set membership. Defined on set types and the types of their
+ members. Same precedence as `<'.
+
+`OR'
+ Boolean disjunction. Defined on boolean types.
+
+`AND, &'
+ Boolean conjuction. Defined on boolean types.
+
+`@'
+ The GDB "artificial array" operator (*note Expressions:
+ Expressions.).
+
+`+, -'
+ Addition and subtraction on integral and floating-point types, or
+ union and difference on set types.
+
+`*'
+ Multiplication on integral and floating-point types, or set
+ intersection on set types.
+
+`/'
+ Division on floating-point types, or symmetric set difference on
+ set types. Same precedence as `*'.
+
+`DIV, MOD'
+ Integer division and remainder. Defined on integral types. Same
+ precedence as `*'.
+
+`-'
+ Negative. Defined on `INTEGER' and `REAL' data.
+
+`^'
+ Pointer dereferencing. Defined on pointer types.
+
+`NOT'
+ Boolean negation. Defined on boolean types. Same precedence as
+ `^'.
+
+`.'
+ `RECORD' field selector. Defined on `RECORD' data. Same
+ precedence as `^'.
+
+`[]'
+ Array indexing. Defined on `ARRAY' data. Same precedence as `^'.
+
+`()'
+ Procedure argument list. Defined on `PROCEDURE' objects. Same
+ precedence as `^'.
+
+`::, .'
+ GDB and Modula-2 scope operators.
+
+ *Warning:* Sets and their operations are not yet supported, so GDB
+ will treat the use of the operator `IN', or the use of operators
+ `+', `-', `*', `/', `=', , `<>', `#', `<=', and `>=' on sets as an
+ error.
+
+
+File: gdb.info, Node: Built-In Func/Proc, Next: M2 Constants, Prev: M2 Operators, Up: Modula-2
+
+Built-in functions and procedures
+---------------------------------
+
+ Modula-2 also makes available several built-in procedures and
+functions. In describing these, the following metavariables are used:
+
+A
+ represents an `ARRAY' variable.
+
+C
+ represents a `CHAR' constant or variable.
+
+I
+ represents a variable or constant of integral type.
+
+M
+ represents an identifier that belongs to a set. Generally used in
+ the same function with the metavariable S. The type of S should
+ be `SET OF MTYPE' (where MTYPE is the type of M).
+
+N
+ represents a variable or constant of integral or floating-point
+ type.
+
+R
+ represents a variable or constant of floating-point type.
+
+T
+ represents a type.
+
+V
+ represents a variable.
+
+X
+ represents a variable or constant of one of many types. See the
+ explanation of the function for details.
+
+ All Modula-2 built-in procedures also return a result, described
+below.
+
+`ABS(N)'
+ Returns the absolute value of N.
+
+`CAP(C)'
+ If C is a lower case letter, it returns its upper case equivalent,
+ otherwise it returns its argument
+
+`CHR(I)'
+ Returns the character whose ordinal value is I.
+
+`DEC(V)'
+ Decrements the value in the variable V. Returns the new value.
+
+`DEC(V,I)'
+ Decrements the value in the variable V by I. Returns the new
+ value.
+
+`EXCL(M,S)'
+ Removes the element M from the set S. Returns the new set.
+
+`FLOAT(I)'
+ Returns the floating point equivalent of the integer I.
+
+`HIGH(A)'
+ Returns the index of the last member of A.
+
+`INC(V)'
+ Increments the value in the variable V. Returns the new value.
+
+`INC(V,I)'
+ Increments the value in the variable V by I. Returns the new
+ value.
+
+`INCL(M,S)'
+ Adds the element M to the set S if it is not already there.
+ Returns the new set.
+
+`MAX(T)'
+ Returns the maximum value of the type T.
+
+`MIN(T)'
+ Returns the minimum value of the type T.
+
+`ODD(I)'
+ Returns boolean TRUE if I is an odd number.
+
+`ORD(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). X must be of an ordered
+ type, which include integral, character and enumerated types.
+
+`SIZE(X)'
+ Returns the size of its argument. X can be a variable or a type.
+
+`TRUNC(R)'
+ Returns the integral part of R.
+
+`VAL(T,I)'
+ Returns the member of the type T whose ordinal value is I.
+
+ *Warning:* Sets and their operations are not yet supported, so
+ GDB will treat the use of procedures `INCL' and `EXCL' as an error.
+
+
+File: gdb.info, Node: M2 Constants, Next: M2 Defaults, Prev: Built-In Func/Proc, Up: Modula-2
+
+Constants
+---------
+
+ GDB allows you to express the constants of Modula-2 in the following
+ways:
+
+ * 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 `H', and octal integers by a trailing `B'.
+
+ * 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 `E[+|-]NNN', where
+ `[+|-]NNN' is the desired exponent. All of the digits of the
+ floating point constant must be valid decimal (base 10) digits.
+
+ * Character constants consist of a single character enclosed by a
+ pair of like quotes, either single (`'') or double (`"'). They may
+ also be expressed by their ordinal value (their ASCII value,
+ usually) followed by a `C'.
+
+ * String constants consist of a sequence of characters enclosed by a
+ pair of like quotes, either single (`'') or double (`"'). Escape
+ sequences in the style of C are also allowed. *Note C and C++
+ constants: C Constants, for a brief explanation of escape
+ sequences.
+
+ * Enumerated constants consist of an enumerated identifier.
+
+ * Boolean constants consist of the identifiers `TRUE' and `FALSE'.
+
+ * Pointer constants consist of integral values only.
+
+ * Set constants are not yet supported.
+
+
+File: gdb.info, Node: M2 Defaults, Next: Deviations, Prev: M2 Constants, Up: Modula-2
+
+Modula-2 defaults
+-----------------
+
+ If type and range checking are set automatically by GDB, they both
+default to `on' whenever the working language changes to Modula-2.
+This happens regardless of whether you, or GDB, selected the working
+language.
+
+ If you allow GDB to set the language automatically, then entering
+code compiled from a file whose name ends with `.mod' will set the
+working language to Modula-2. *Note Having GDB set the language
+automatically: Automatically, for further details.
+
+
+File: gdb.info, Node: Deviations, Next: M2 Checks, Prev: M2 Defaults, Up: Modula-2
+
+Deviations from standard Modula-2
+---------------------------------
+
+ A few changes have been made to make Modula-2 programs easier to
+debug. This is done primarily via loosening its type strictness:
+
+ * 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.)
+
+ * C escape sequences can be used in strings and characters to
+ represent non-printable characters. GDB will print out strings
+ with these escape sequences embedded. Single non-printable
+ characters are printed using the `CHR(NNN)' format.
+
+ * The assignment operator (`:=') returns the value of its right-hand
+ argument.
+
+ * All built-in procedures both modify *and* return their argument.
+
+
+File: gdb.info, Node: M2 Checks, Next: M2 Scope, Prev: Deviations, Up: Modula-2
+
+Modula-2 type and range checks
+------------------------------
+
+ *Warning:* in this release, GDB does not yet perform type or range
+ checking.
+
+ GDB considers two Modula-2 variables type equivalent if:
+
+ * They are of types that have been declared equivalent via a `TYPE
+ T1 = T2' statement
+
+ * 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.)
+
+ 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.
+
+
+File: gdb.info, Node: M2 Scope, Next: GDB/M2, Prev: M2 Checks, Up: Modula-2
+
+The scope operators `::' and `.'
+--------------------------------
+
+ There are a few subtle differences between the Modula-2 scope
+operator (`.') and the GDB scope operator (`::'). The two have similar
+syntax:
+
+
+ MODULE . ID
+ SCOPE :: ID
+
+where SCOPE is the name of a module or a procedure, MODULE the name of
+a module, and ID is any declared identifier within your program, except
+another module.
+
+ Using the `::' operator makes GDB search the scope specified by
+SCOPE for the identifier ID. If it is not found in the specified
+scope, then GDB will search all scopes enclosing the one specified by
+SCOPE.
+
+ Using the `.' operator makes GDB search the current scope for the
+identifier specified by ID that was imported from the definition module
+specified by MODULE. With this operator, it is an error if the
+identifier ID was not imported from definition module MODULE, or if ID
+is not an identifier in MODULE.
+
+
+File: gdb.info, Node: GDB/M2, Prev: M2 Scope, Up: Modula-2
+
+GDB and Modula-2
+----------------
+
+ Some GDB commands have little use when debugging Modula-2 programs.
+Five subcommands of `set print' and `show print' apply specifically to
+C and C++: `vtbl', `demangle', `asm-demangle', `object', and `union'.
+The first four apply to C++, and the last to the C `union' type, which
+has no direct analogue in Modula-2.
+
+ The `@' operator (*note Expressions: Expressions.), while available
+while using any language, is not useful with Modula-2. Its intent is
+to aid the debugging of "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 `{TYPE}ADREXP' is
+still useful. (*note Expressions: Expressions.)
+
+ In GDB scripts, the Modula-2 inequality operator `#' is interpreted
+as the beginning of a comment. Use `<>' instead.
+
+
+File: gdb.info, Node: Symbols, Next: Altering, Prev: Languages, Up: Top
+
+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. GDB finds it in your
+program's symbol table, in the file indicated when you started GDB
+(*note Choosing files: File Options.), or by one of the file-management
+commands (*note Commands to specify files: Files.).
+
+ Occasionally, you may need to refer to symbols that contain unusual
+characters, which GDB ordinarily treats as word delimiters. The most
+frequent case is in referring to static variables in other source files
+(*note Program variables: Variables.). File names are recorded in
+object files as debugging symbols, but GDB would ordinarily parse a
+typical file name, like `foo.c', as the three words `foo' `.' `c'. To
+allow GDB to recognize `foo.c' as a single symbol, enclose it in single
+quotes; for example,
+
+ p 'foo.c'::x
+
+looks up the value of `x' in the scope of the file `foo.c'.
+
+`info address SYMBOL'
+ Describe where the data for 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 `print &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.
+
+`whatis EXP'
+ Print the data type of expression EXP. EXP is not actually
+ evaluated, and any side-effecting operations (such as assignments
+ or function calls) inside it do not take place. *Note
+ Expressions: Expressions.
+
+`whatis'
+ Print the data type of `$', the last value in the value history.
+
+`ptype TYPENAME'
+ Print a description of data type TYPENAME. TYPENAME may be the
+ name of a type, or for C code it may have the form `class
+ CLASS-NAME', `struct STRUCT-TAG', `union UNION-TAG' or `enum
+ ENUM-TAG'.
+
+`ptype EXP'
+`ptype'
+ Print a description of the type of expression EXP. `ptype'
+ differs from `whatis' by printing a detailed description, instead
+ of just the name of the type.
+
+ For example, for this variable declaration:
+
+ struct complex {double real; double imag;} v;
+
+ the two commands give this output:
+
+ (gdb) whatis v
+ type = struct complex
+ (gdb) ptype v
+ type = struct complex {
+ double real;
+ double imag;
+ }
+
+ As with `whatis', using `ptype' without an argument refers to the
+ type of `$', the last value in the value history.
+
+`info types REGEXP'
+`info types'
+ Print a brief description of all types whose name matches 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, `i type value' gives information on all types in your
+ program whose name includes the string `value', but `i type
+ ^value$' gives information only on types whose complete name is
+ `value'.
+
+ This command differs from `ptype' in two ways: first, like
+ `whatis', it does not print a detailed description; second, it
+ lists all source files where a type is defined.
+
+`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.
+
+`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.
+
+`info functions'
+ Print the names and data types of all defined functions.
+
+`info functions REGEXP'
+ Print the names and data types of all defined functions whose
+ names contain a match for regular expression REGEXP. Thus, `info
+ fun step' finds all functions whose names include `step'; `info
+ fun ^step' finds those whose names start with `step'.
+
+`info variables'
+ Print the names and data types of all variables that are declared
+ outside of functions (i.e., excluding local variables).
+
+`info variables REGEXP'
+ Print the names and data types of all variables (except for local
+ variables) whose names contain a match for regular expression
+ REGEXP.
+
+`maint print symbols FILENAME'
+`maint print psymbols FILENAME'
+`maint print msymbols FILENAME'
+ Write a dump of debugging symbol data into the file FILENAME.
+ These commands are used to debug the GDB symbol-reading code. Only
+ symbols with debugging data are included. If you use `maint print
+ symbols', GDB includes all the symbols for which it has already
+ collected full details: that is, FILENAME reflects symbols for
+ only those files whose symbols GDB has read. You can use the
+ command `info sources' to find out which files these are. If you
+ use `maint print psymbols' instead, the dump shows information
+ about symbols that GDB only knows partially--that is, symbols
+ defined in files that GDB has skimmed, but not yet read
+ completely. Finally, `maint print msymbols' dumps just the
+ minimal symbol information required for each object file from
+ which GDB has read some symbols. *Note Commands to specify files:
+ Files, for a discussion of how GDB reads symbols (in the
+ description of `symbol-file').
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-5 b/gnu/usr.bin/gdb/doc/gdb.info-5
new file mode 100644
index 0000000..ecf3d18
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-5
@@ -0,0 +1,1215 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ 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.
+
+ 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.
+
+
+File: gdb.info, Node: Altering, Next: GDB Files, Prev: Symbols, Up: Top
+
+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 GDB features for altering execution of
+the program.
+
+ For example, you can store new values into variables or memory
+locations, give your program a signal, restart it 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
+
+* Signaling:: Giving your program a signal
+
+* Returning:: Returning from a function
+* Calling:: Calling your program's functions
+* Patching:: Patching your program
+
+
+File: gdb.info, Node: Assignment, Next: Jumping, Up: Altering
+
+Assignment to variables
+=======================
+
+ To alter the value of a variable, evaluate an assignment expression.
+*Note Expressions: Expressions. For example,
+
+ print x=4
+
+stores the value 4 into the variable `x', and then prints the value of
+the assignment expression (which is 4). *Note Using GDB with Different
+Languages: Languages, for more information on operators in supported
+languages.
+
+ If you are not interested in seeing the value of the assignment, use
+the `set' command instead of the `print' command. `set' is really the
+same as `print' except that the expression's value is not printed and
+is not put in the value history (*note Value history: Value History.).
+The expression is evaluated only for its effects.
+
+ If the beginning of the argument string of the `set' command appears
+identical to a `set' subcommand, use the `set variable' command instead
+of just `set'. This command is identical to `set' except for its lack
+of subcommands. For example, if your program has a variable `width',
+you get an error if you try to set a new value with just `set width=13',
+because GDB has the command `set width':
+
+ (gdb) whatis width
+ type = double
+ (gdb) p width
+ $4 = 13
+ (gdb) set width=47
+ Invalid syntax in expression.
+
+The invalid expression, of course, is `=47'. In order to actually set
+the program's variable `width', use
+
+ (gdb) set var width=47
+
+ GDB 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.
+
+ To store values into arbitrary places in memory, use the `{...}'
+construct to generate a value of specified type at a specified address
+(*note Expressions: Expressions.). For example, `{int}0x83040' refers
+to memory location `0x83040' as an integer (which implies a certain size
+and representation in memory), and
+
+ set {int}0x83040 = 4
+
+stores the value 4 into that memory location.
+
+
+File: gdb.info, Node: Jumping, Next: Signaling, Prev: Assignment, Up: Altering
+
+Continuing at a different address
+=================================
+
+ Ordinarily, when you continue your program, you do so at the place
+where it stopped, with the `continue' command. You can instead
+continue at an address of your own choosing, with the following
+commands:
+
+`jump LINESPEC'
+ Resume execution at line LINESPEC. Execution will stop
+ immediately if there is a breakpoint there. *Note Printing source
+ lines: List, for a description of the different forms of LINESPEC.
+
+ The `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 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 `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.
+
+`jump *ADDRESS'
+ Resume execution at the instruction at address ADDRESS.
+
+ You can get much the same effect as the `jump' command by storing a
+new value into the register `$pc'. The difference is that this does
+not start your program running; it only changes the address where it
+*will* run when it is continued. For example,
+
+ set $pc = 0x485
+
+causes the next `continue' command or stepping command to execute at
+address `0x485', rather than at the address where your program stopped.
+*Note Continuing and stepping: Continuing and Stepping.
+
+ The most common occasion to use the `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.
+
+
+File: gdb.info, Node: Signaling, Next: Returning, Prev: Jumping, Up: Altering
+
+Giving your program a signal
+============================
+
+`signal SIGNAL'
+ Resume execution where your program stopped, but immediately give
+ it the signal SIGNAL. SIGNAL can be the name or the number of a
+ signal. For example, on many systems `signal 2' and `signal
+ SIGINT' are both ways of sending an interrupt signal.
+
+ Alternatively, if 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 `continue' command; `signal 0' causes it to resume
+ without a signal.
+
+ `signal' does not repeat when you press RET a second time after
+ executing the command.
+
+ Invoking the `signal' command is not the same as invoking the `kill'
+utility from the shell. Sending a signal with `kill' causes GDB to
+decide what to do with the signal depending on the signal handling
+tables (*note Signals::.). The `signal' command passes the signal
+directly to your program.
+
+
+File: gdb.info, Node: Returning, Next: Calling, Prev: Signaling, Up: Altering
+
+Returning from a function
+=========================
+
+`return'
+`return EXPRESSION'
+ You can cancel execution of a function call with the `return'
+ command. If you give an EXPRESSION argument, its value is used as
+ the function's return value.
+
+ When you use `return', GDB 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 `return'.
+
+ This pops the selected stack frame (*note Selecting a frame:
+Selection.), 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 `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 `finish' command (*note Continuing and
+stepping: Continuing and Stepping.) resumes execution until the
+selected stack frame returns naturally.
+
+
+File: gdb.info, Node: Calling, Next: Patching, Prev: Returning, Up: Altering
+
+Calling program functions
+=========================
+
+`call EXPR'
+ Evaluate the expression EXPR without displaying `void' returned
+ values.
+
+ You can use this variant of the `print' command if you want to
+execute a function from your program, but without cluttering the output
+with `void' returned values. The result is printed and saved in the
+value history, if it is not void.
+
+
+File: gdb.info, Node: Patching, Prev: Calling, Up: Altering
+
+Patching programs
+=================
+
+ By default, GDB opens the file containing your program's executable
+code (or the corefile) 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 `set write' command. For example, you might want
+to turn on internal debugging flags, or even to make emergency repairs.
+
+`set write on'
+`set write off'
+ If you specify `set write on', GDB will open executable and core
+ files for both reading and writing; if you specify `set write off'
+ (the default), GDB will open them read-only.
+
+ If you have already loaded a file, you must load it again (using
+ the `exec-file' or `core-file' command) after changing `set
+ write', for your new setting to take effect.
+
+`show write'
+ Display whether executable files and core files will be opened for
+ writing as well as reading.
+
+
+File: gdb.info, Node: GDB Files, Next: Targets, Prev: Altering, Up: Top
+
+GDB Files
+*********
+
+ GDB 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.
+To debug a core dump of a previous run, you must also tell GDB the name
+of the core dump file.
+
+* Menu:
+
+* Files:: Commands to specify files
+* Symbol Errors:: Errors reading symbol files
+
+
+File: gdb.info, Node: Files, Next: Symbol Errors, Up: GDB Files
+
+Commands to specify files
+=========================
+
+ The usual way to specify executable and core dump file names is with
+the command arguments given when you start GDB (*note Getting In and
+Out of GDB: Invocation..
+
+ Occasionally it is necessary to change to a different file during a
+GDB session. Or you may run GDB and forget to specify a file you want
+to use. In these situations the GDB commands to specify new files are
+useful.
+
+`file FILENAME'
+ Use 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 `run' command. If you do not
+ specify a directory and the file is not found in the GDB working
+ directory, GDB uses the environment variable `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 GDB and your program, using the `path' command.
+
+ On systems with memory-mapped files, an auxiliary symbol table file
+ `FILENAME.syms' may be available for FILENAME. If it is, GDB will
+ map in the symbol table from `FILENAME.syms', starting up more
+ quickly. See the descriptions of the options `-mapped' and
+ `-readnow' (available on the command line, and with the commands
+ `file', `symbol-file', or `add-symbol-file'), for more information.
+
+`file'
+ `file' with no argument makes GDB discard any information it has
+ on both executable file and the symbol table.
+
+`exec-file [ FILENAME ]'
+ Specify that the program to be run (but not the symbol table) is
+ found in FILENAME. GDB will search the environment variable `PATH'
+ if necessary to locate your program. Omitting FILENAME means to
+ discard information on the executable file.
+
+`symbol-file [ FILENAME ]'
+ Read symbol table information from file FILENAME. `PATH' is
+ searched when necessary. Use the `file' command to get both symbol
+ table and program to run from the same file.
+
+ `symbol-file' with no argument clears out GDB information on your
+ program's symbol table.
+
+ The `symbol-file' command causes GDB 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
+ GDB.
+
+ `symbol-file' will not repeat if you press RET again after
+ executing it once.
+
+ When GDB is configured for a particular environment, it will
+ understand 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 `gcc' you can generate debugging information for optimized
+ code.
+
+ On some kinds of object files, the `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 GDB
+ 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 `set verbose' command can turn
+ these pauses into messages if desired. *Note Optional warnings
+ and messages: Messages/Warnings.)
+
+ We have not implemented the two-stage strategy for COFF yet. When
+ the symbol table is stored in COFF format, `symbol-file' reads the
+ symbol table data in full right away.
+
+`symbol-file FILENAME [ -readnow ] [ -mapped ]'
+`file FILENAME [ -readnow ] [ -mapped ]'
+ You can override the GDB two-stage strategy for reading symbol
+ tables by using the `-readnow' option with any of the commands that
+ load symbol table information, if you want to be sure GDB has the
+ entire symbol table available.
+
+ If memory-mapped files are available on your system through the
+ `mmap' system call, you can use another option, `-mapped', to
+ cause GDB to write the symbols for your program into a reusable
+ file. Future GDB debugging sessions will 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 `-mapped' option has the same
+ effect as starting GDB with the `-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 MYPROG is called
+ `MYPROG.syms'. Once this file exists (so long as it is newer than
+ the corresponding executable), GDB will always attempt to use it
+ when you debug MYPROG; no special options or commands are needed.
+
+ The `.syms' file is specific to the host machine where you run
+ GDB. It holds an exact image of the internal GDB symbol table.
+ It cannot be shared across multiple host platforms.
+
+`core-file [ FILENAME ]'
+ 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; GDB
+ can access the executable file itself for other parts.
+
+ `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 GDB. 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
+ `kill' command (*note Killing the child process: Kill Process.).
+
+`load FILENAME'
+ Depending on what remote debugging facilities are configured into
+ GDB, the `load' command may be available. Where it exists, it is
+ meant to make FILENAME (an executable) available for debugging on
+ the remote system--by downloading, or dynamic linking, for example.
+ `load' also records the FILENAME symbol table in GDB, like the
+ `add-symbol-file' command.
+
+ If your GDB does not have a `load' command, attempting to execute
+ it gets the error message "`You can't do that when your target is
+ ...'"
+
+ The file is loaded at whatever address is specified in the
+ executable. For some object file formats, like a.out, the object
+ file format fixes the address and so it won't necessarily match
+ the address you gave to the linker.
+
+ On VxWorks, `load' will dynamically link FILENAME on the current
+ target system as well as adding its symbols in GDB.
+
+ With the Nindy interface to an Intel 960 board, `load' will
+ download FILENAME to the 960 as well as adding its symbols in GDB.
+
+ When you select remote debugging to a Hitachi SH, H8/300, or
+ H8/500 board (*note GDB and Hitachi Microprocessors: Hitachi
+ Remote.), the `load' command downloads your program to the Hitachi
+ board and also opens it as the current executable target for GDB
+ on your host (like the `file' command).
+
+ `load' will not repeat if you press RET again after using it.
+
+`add-symbol-file FILENAME ADDRESS'
+`add-symbol-file FILENAME ADDRESS [ -readnow ] [ -mapped ]'
+ The `add-symbol-file' command reads additional symbol table
+ information from the file FILENAME. You would use this command
+ when FILENAME has been dynamically loaded (by some other means)
+ into the program that is running. ADDRESS should be the memory
+ address at which the file has been loaded; GDB cannot figure this
+ out for itself. You can specify ADDRESS as an expression.
+
+ The symbol table of the file FILENAME is added to the symbol table
+ originally read with the `symbol-file' command. You can use the
+ `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 `symbol-file' command.
+
+ `add-symbol-file' will not repeat if you press RET after using it.
+
+ You can use the `-mapped' and `-readnow' options just as with the
+ `symbol-file' command, to change how GDB manages the symbol table
+ information for FILENAME.
+
+`info files'
+`info target'
+ `info files' and `info target' are synonymous; both print the
+ current target (*note Specifying a Debugging Target: Targets.),
+ including the names of the executable and core dump files
+ currently in use by GDB, and the files from which symbols were
+ loaded. The command `help targets' lists all possible targets
+ rather than current ones.
+
+ All file-specifying commands allow both absolute and relative file
+names as arguments. GDB always converts the file name to an absolute
+path name and remembers it that way.
+
+ GDB supports SunOS, SVR4, and IBM RS/6000 shared libraries. GDB
+automatically loads symbol definitions from shared libraries when you
+use the `run' command, or when you examine a core file. (Before you
+issue the `run' command, GDB will not understand references to a
+function in a shared library, however--unless you are debugging a core
+file).
+
+`info share'
+`info sharedlibrary'
+ Print the names of the shared libraries which are currently loaded.
+
+`sharedlibrary REGEX'
+`share REGEX'
+ 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 will only
+ load shared libraries required by your program for a core file or
+ after typing `run'. If REGEX is omitted all shared libraries
+ required by your program are loaded.
+
+
+File: gdb.info, Node: Symbol Errors, Prev: Files, Up: GDB Files
+
+Errors reading symbol files
+===========================
+
+ While reading a symbol file, GDB will occasionally encounter
+problems, such as symbol types it does not recognize, or known bugs in
+compiler output. By default, GDB 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 GDB to print only one
+message about each such type of problem, no matter how many times the
+problem occurs; or you can ask GDB to print more messages, to see how
+many times the problems occur, with the `set complaints' command (*note
+Optional warnings and messages: Messages/Warnings.).
+
+ The messages currently printed, and their meanings, include:
+
+`inner block not inside outer block in 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.
+
+ GDB circumvents the problem by treating the inner block as if it
+ had the same scope as the outer block. In the error message,
+ SYMBOL may be shown as "`(don't know)'" if the outer block is not a
+ function.
+
+`block at 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.
+
+ GDB does not circumvent this problem, and will have trouble
+ locating symbols in the source file whose symbols it is reading.
+ (You can often determine what source file is affected by specifying
+ `set verbose on'. *Note Optional warnings and messages:
+ Messages/Warnings.)
+
+`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.
+
+ GDB circumvents the problem by treating the symbol scope block as
+ starting on the previous source line.
+
+`bad string table offset in symbol N'
+ Symbol number N contains a pointer into the string table which is
+ larger than the size of the string table.
+
+ GDB circumvents the problem by considering the symbol to have the
+ name `foo', which may cause other problems if many symbols end up
+ with this name.
+
+`unknown symbol type `0xNN''
+ The symbol information contains new data types that GDB does not
+ yet know how to read. `0xNN' is the symbol type of the
+ misunderstood information, in hexadecimal.
+
+ GDB circumvents the error by ignoring this symbol information.
+ This will usually allow your program to be debugged, though
+ certain symbols will not be accessible. If you encounter such a
+ problem and feel like debugging it, you can debug `gdb' with
+ itself, breakpoint on `complain', then go up to the function
+ `read_dbx_symtab' and examine `*bufp' to see the symbol.
+
+`stub type has NULL name'
+ GDB could not find the full definition for a struct or class.
+
+`const/volatile indicator missing (ok if using g++ v1.x), got...'
+ The symbol information for a C++ member function is missing some
+ information that recent versions of the compiler should have output
+ for it.
+
+`info mismatch between compiler and debugger'
+ GDB could not parse a type specification output by the compiler.
+
+
+File: gdb.info, Node: Targets, Next: Controlling GDB, Prev: GDB Files, Up: Top
+
+Specifying a Debugging Target
+*****************************
+
+ A "target" is the execution environment occupied by your program.
+Often, GDB 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 `file' or `core' commands. When you need more flexibility--for
+example, running GDB on a physically separate host, or controlling a
+standalone system over a serial port or a realtime system over a TCP/IP
+connection--you can use the `target' command to specify one of the
+target types configured for GDB (*note Commands for managing targets:
+Target Commands.).
+
+* Menu:
+
+* Active Targets:: Active targets
+* Target Commands:: Commands for managing targets
+* Remote:: Remote debugging
+
+
+File: gdb.info, Node: Active Targets, Next: Target Commands, Up: Targets
+
+Active targets
+==============
+
+ There are three classes of targets: processes, core files, and
+executable files. GDB 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 `gdb a.out', then the executable file
+`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 GDB
+has two active targets and will use 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.)
+
+ When you type `run', your executable file becomes an active process
+target as well. When a process target is active, all GDB commands
+requesting memory addresses refer to that target; addresses in an
+active core file or executable file target are obscured while the
+process target is active.
+
+ Use the `core-file' and `exec-file' commands to select a new core
+file or executable target (*note Commands to specify files: Files.).
+To specify as a target a process that is already running, use the
+`attach' command (*note Debugging an already-running process: Attach.).
+
+
+File: gdb.info, Node: Target Commands, Next: Remote, Prev: Active Targets, Up: Targets
+
+Commands for managing targets
+=============================
+
+`target TYPE PARAMETERS'
+ Connects the GDB host environment to a target machine or process.
+ A target is typically a protocol for talking to debugging
+ facilities. You use the argument TYPE to specify the type or
+ protocol of the target machine.
+
+ Further 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.
+
+ The `target' command will not repeat if you press RET again after
+ executing the command.
+
+`help target'
+ Displays the names of all targets available. To display targets
+ currently selected, use either `info target' or `info files'
+ (*note Commands to specify files: Files.).
+
+`help target NAME'
+ Describe a particular target, including any parameters necessary to
+ select it.
+
+ Here are some common targets (available, or not, depending on the GDB
+configuration):
+
+`target exec PROGRAM'
+ An executable file. `target exec PROGRAM' is the same as
+ `exec-file PROGRAM'.
+
+`target core FILENAME'
+ A core dump file. `target core FILENAME' is the same as
+ `core-file FILENAME'.
+
+`target remote DEV'
+ Remote serial target in GDB-specific protocol. The argument DEV
+ specifies what serial device to use for the connection (e.g.
+ `/dev/ttya'). *Note Remote debugging: Remote.
+
+`target sim'
+ CPU simulator. *Note Simulated CPU Target: Simulator.
+
+`target udi KEYWORD'
+ Remote AMD29K target, using the AMD UDI protocol. The KEYWORD
+ argument specifies which 29K board or simulator to use. *Note GDB
+ and the UDI protocol for AMD29K: UDI29K Remote.
+
+`target amd-eb DEV SPEED PROG'
+ Remote PC-resident AMD EB29K board, attached over serial lines.
+ dEV is the serial device, as for `target remote'; SPEED allows you
+ to specify the linespeed; and PROG is the name of the program to
+ be debugged, as it appears to DOS on the PC. *Note GDB with a
+ remote EB29K: EB29K Remote.
+
+`target hms'
+ A Hitachi SH, H8/300, or H8/500 board, attached via serial line to
+ your host. Use special commands `device' and `speed' to control
+ the serial line and the communications speed used. *Note GDB and
+ Hitachi Microprocessors: Hitachi Remote.
+
+`target nindy DEVICENAME'
+ An Intel 960 board controlled by a Nindy Monitor. DEVICENAME is
+ the name of the serial device to use for the connection, e.g.
+ `/dev/ttya'. *Note GDB with a remote i960 (Nindy): i960-Nindy
+ Remote.
+
+`target st2000 DEV SPEED'
+ A Tandem ST2000 phone switch, running Tandem's STDBUG protocol.
+ dEV is the name of the device attached to the ST2000 serial line;
+ SPEED is the communication line speed. The arguments are not used
+ if GDB is configured to connect to the ST2000 using TCP or Telnet.
+ *Note GDB with a Tandem ST2000: ST2000 Remote.
+
+`target vxworks MACHINENAME'
+ A VxWorks system, attached via TCP/IP. The argument MACHINENAME
+ is the target system's machine name or IP address. *Note GDB and
+ VxWorks: VxWorks Remote.
+
+ Different targets are available on different configurations of GDB;
+your configuration may have more or fewer targets.
+
+
+File: gdb.info, Node: Remote, Prev: Target Commands, Up: Targets
+
+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 will run on the remote system to
+communicate with GDB.
+
+ Other remote targets may be available in your configuration of GDB;
+use `help targets' to list them.
+
+* Menu:
+
+
+* Remote Serial:: GDB remote serial protocol
+
+* i960-Nindy Remote:: GDB with a remote i960 (Nindy)
+
+* UDI29K Remote:: GDB and the UDI protocol for AMD29K
+* EB29K Remote:: GDB with a remote EB29K
+
+* VxWorks Remote:: GDB and VxWorks
+
+* ST2000 Remote:: GDB with a Tandem ST2000
+
+* Hitachi Remote:: GDB and Hitachi Microprocessors
+
+* MIPS Remote:: GDB and MIPS boards
+
+* Simulator:: Simulated CPU target
+
+
+File: gdb.info, Node: Remote Serial, Next: i960-Nindy Remote, Up: Remote
+
+The GDB remote serial protocol
+------------------------------
+
+ To debug a program running on another machine (the debugging
+"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
+
+ 1. A startup routine to set up the C runtime environment; these
+ usually have a name like `crt0'. The startup routine may be
+ supplied by your hardware supplier, or you may have to write your
+ own.
+
+ 2. You probably need a C subroutine library to support your program's
+ subroutine calls, notably managing input and output.
+
+ 3. 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.
+
+ The next step is to arrange for your program to use a serial port to
+communicate with the machine where GDB is running (the "host" machine).
+In general terms, the scheme looks like this:
+
+*On the host,*
+ GDB already understands how to use this protocol; when everything
+ else is set up, you can simply use the `target remote' command
+ (*note Specifying a Debugging Target: Targets.).
+
+*On the target,*
+ you must link with your program a few special-purpose subroutines
+ that implement the GDB remote serial protocol. The file
+ containing these subroutines is called a "debugging stub".
+
+ On certain remote targets, you can use an auxiliary program
+ `gdbserver' instead of linking a stub into your program. *Note
+ Using the `gdbserver' program: Server, for details.
+
+ The debugging stub is specific to the architecture of the remote
+machine; for example, use `sparc-stub.c' to debug programs on SPARC
+boards.
+
+ These working remote stubs are distributed with GDB:
+
+`sparc-stub.c'
+ For SPARC architectures.
+
+`m68k-stub.c'
+ For Motorola 680x0 architectures.
+
+`i386-stub.c'
+ For Intel 386 and compatible architectures.
+
+ The `README' file in the GDB 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
+
+* Server:: Using the `gdbserver' program
+
+
+File: gdb.info, Node: Stub Contents, Next: Bootstrapping, Up: Remote Serial
+
+What the stub can do for you
+----------------------------
+
+ The debugging stub for your architecture supplies these three
+subroutines:
+
+`set_debug_traps'
+ This routine arranges for `handle_exception' to run when your
+ program stops. You must call this subroutine explicitly near the
+ beginning of your program.
+
+`handle_exception'
+ This is the central workhorse, but your program never calls it
+ explicitly--the setup code arranges for `handle_exception' to run
+ when a trap is triggered.
+
+ `handle_exception' takes control when your program stops during
+ execution (for example, on a breakpoint), and mediates
+ communications with GDB on the host machine. This is where the
+ communications protocol is implemented; `handle_exception' acts as
+ the GDB 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 GDB needs,
+ until you execute a GDB command that makes your program resume; at
+ that point, `handle_exception' returns control to your own code on
+ the target machine.
+
+`breakpoint'
+ Use this auxiliary subroutine to make your program contain a
+ breakpoint. Depending on the particular situation, this may be
+ the only way for GDB 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 will transfer control to
+ `handle_exception'--in effect, to GDB. 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 `breakpoint' from
+ your own program--simply running `target remote' from the host GDB
+ session will get control.
+
+ Call `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.
+
+
+File: gdb.info, Node: Bootstrapping, Next: Debug Session, Prev: Stub Contents, Up: Remote Serial
+
+What you must do for the stub
+-----------------------------
+
+ The debugging stubs that come with GDB are set up for a particular
+chip architecture, but they have no information about the rest of your
+debugging target machine. To allow the stub to work, you must supply
+these special low-level subroutines:
+
+`int getDebugChar()'
+ Write this subroutine to read a single character from the serial
+ port. It may be identical to `getchar' for your target system; a
+ different name is used to allow you to distinguish the two if you
+ wish.
+
+`void putDebugChar(int)'
+ Write this subroutine to write a single character to the serial
+ port. It may be identical to `putchar' for your target system; a
+ different name is used to allow you to distinguish the two if you
+ wish.
+
+`void exceptionHandler (int EXCEPTION_NUMBER, void *EXCEPTION_ADDRESS)'
+ Write this function to install 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 ROM, containing entries which point to a table in RAM).
+ 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 EXCEPTION_ADDRESS, and the processor state (stack, registers,
+ etc.) should be just as it is when a processor exception occurs.
+ So if you want to use a jump instruction to reach
+ EXCEPTION_ADDRESS, it should be a simple jump, not a jump to
+ subroutine.
+
+ For the 386, 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 SPARC and 68k stubs are able to mask interrupts themself
+ without help from `exceptionHandler'.
+
+`void 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, GDB requires this
+ function to make certain that the state of your program is stable.
+
+You must also make sure this library routine is available:
+
+`void *memset(void *, int, int)'
+ This is the standard library function `memset' that sets an area of
+ memory to a known value. If you have one of the free versions of
+ `libc.a', `memset' can be found there; otherwise, you must either
+ obtain it from your hardware manufacturer, or write your own.
+
+ If you do not use the GNU C compiler, you may need other standard
+library subroutines as well; this will vary from one stub to another,
+but in general the stubs are likely to use any of the common library
+subroutines which `gcc' generates as inline code.
+
+
+File: gdb.info, Node: Debug Session, Next: Protocol, Prev: Bootstrapping, Up: Remote Serial
+
+Putting it all together
+-----------------------
+
+ In summary, when your program is ready to debug, you must follow
+these steps.
+
+ 1. Make sure you have the supporting low-level routines (*note What
+ you must do for the stub: Bootstrapping.):
+ `getDebugChar', `putDebugChar',
+ `flush_i_cache', `memset', `exceptionHandler'.
+
+ 2. Insert these lines near the top of your program:
+
+ set_debug_traps();
+ breakpoint();
+
+ 3. For the 680x0 stub only, you need to provide a variable called
+ `exceptionHook'. Normally you just use
+
+ void (*exceptionHook)() = 0;
+
+ but if before calling `set_debug_traps', you set it to point to a
+ function in your program, that function is called when `GDB'
+ continues after stopping on a trap (for example, bus error). The
+ function indicated by `exceptionHook' is called with one
+ parameter: an `int' which is the exception number.
+
+ 4. Compile and link together: your program, the GDB debugging stub for
+ your target architecture, and the supporting subroutines.
+
+ 5. Make sure you have a serial connection between your target machine
+ and the GDB host, and identify the serial port used for this on
+ the host.
+
+ 6. Download your program to your target machine (or get it there by
+ whatever means the manufacturer provides), and start it.
+
+ 7. To start remote debugging, run GDB on the host machine, and specify
+ as an executable file the program that is running in the remote
+ machine. This tells GDB how to find your program's symbols and
+ the contents of its pure text.
+
+ Then establish communication using the `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 `/dev/ttyb':
+
+ target remote /dev/ttyb
+
+ To use a TCP connection, use an argument of the form `HOST:port'.
+ For example, to connect to port 2828 on a terminal server named
+ `manyfarms':
+
+ target remote manyfarms:2828
+
+ 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 `detach'
+command.
+
+ Whenever GDB is waiting for the remote program, if you type the
+interrupt character (often C-C), GDB 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, GDB displays this prompt:
+
+ Interrupted while waiting for the program.
+ Give up (and stop debugging it)? (y or n)
+
+ If you type `y', GDB abandons the remote debugging session. (If you
+decide you want to try again later, you can use `target remote' again
+to connect once more.) If you type `n', GDB goes back to waiting.
+
+
+File: gdb.info, Node: Protocol, Next: Server, Prev: Debug Session, Up: Remote Serial
+
+Outline of the communication protocol
+-------------------------------------
+
+ The stub files provided with GDB implement the target side of the
+communication protocol, and the GDB side is implemented in the GDB
+source 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. `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 GDB.
+
+ All GDB 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 `$', and ends with the
+character `#' followed by a two-digit checksum:
+
+ $PACKET INFO#CHECKSUM
+
+CHECKSUM is computed as the modulo 256 sum of the 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 `+' (to indicate the package was received correctly) or `-' (to
+request retransmission).
+
+ The host (GDB) 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:
+
+`g'
+ Requests the values of CPU registers.
+
+`G'
+ Sets the values of CPU registers.
+
+`mADDR,COUNT'
+ Read COUNT bytes at location ADDR.
+
+`MADDR,COUNT:...'
+ Write COUNT bytes at location ADDR.
+
+`c'
+`cADDR'
+ Resume execution at the current address (or at ADDR if supplied).
+
+`s'
+`sADDR'
+ Step the target program for one instruction, from either the
+ current program counter or from ADDR if supplied.
+
+`k'
+ Kill the target program.
+
+`?'
+ Report the most recent signal. To allow you to take advantage of
+ the GDB signal handling commands, one of the functions of the
+ debugging stub is to report CPU traps as the corresponding POSIX
+ signal values.
+
+ If you have trouble with the serial connection, you can use the
+command `set remotedebug'. This makes GDB report on all packets sent
+back and forth across the serial line to the remote machine. The
+packet-debugging information is printed on the GDB standard output
+stream. `set remotedebug off' turns it off, and `show remotedebug'
+will show you its current state.
+
+
+File: gdb.info, Node: Server, Prev: Protocol, Up: Remote Serial
+
+Using the `gdbserver' program
+-----------------------------
+
+ `gdbserver' is a control program for Unix-like systems, which allows
+you to connect your program with a remote GDB via `target remote'--but
+without linking in the usual debugging stub.
+
+ `gdbserver' is not a complete replacement for the debugging stubs,
+because it requires essentially the same operating-system facilities
+that GDB itself does. In fact, a system that can run `gdbserver' to
+connect to a remote GDB could also run GDBN locally! `gdbserver' is
+sometimes useful nevertheless, because it is a much smaller program
+than GDB itself. It is also easier to port than all of GDBN, so you
+may be able to get started more quickly on a new system by using
+`gdbserver'.
+
+ GDB and `gdbserver' communicate via either a serial line or a TCP
+connection, using the standard GDB remote serial protocol.
+
+*On the target,*
+ you need to have a copy of the program you want to debug.
+ `gdbserver' does not need your program's symbol table, so you can
+ strip the program if necessary to save space. GDB on the host
+ system does all the symbol handling.
+
+ To use the server, you must tell it how to communicate with {No
+ Value For "GDB"}; the name of your program; and the arguments for
+ your program. The syntax is:
+
+ target> gdbserver COMM PROGRAM [ ARGS ... ]
+
+ 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 `foo.txt' and communicate with GDB over the serial port
+ `/dev/com1':
+
+ target> gdbserver /dev/com1 emacs foo.txt
+
+ `gdbserver' waits passively for the host GDB to communicate with
+ it.
+
+ To use a TCP connection instead of a serial line:
+
+ target> gdbserver host:2345 emacs foo.txt
+
+ The only difference from the previous example is the first
+ argument, specifying that you are communicating with the host GDB
+ via TCP. The `host:2345' argument means that `gdbserver' is to
+ expect a TCP connection from machine `host' to local TCP port 2345.
+ (Currently, the `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.(1) You must use
+ the same port number with the host GDB `target remote' command.
+
+*On the host,*
+ you need an unstripped copy of your program, since GDB needs
+ symbols and debugging information. Start up GDB as usual, using
+ the name of the local copy of your program as the first argument.
+ (You may also need the `--baud' option if the serial line is
+ running at anything other than 9600 bps.) After that, use `target
+ remote' to establish communications with `gdbserver'. Its
+ argument is either a device name (usually a serial device, like
+ `/dev/ttyb'), or a TCP port descriptof in the form `HOST:PORT'.
+ For example:
+
+ (gdb) target remote /dev/ttyb
+
+ communicates with the server via serial line `/dev/ttyb', and
+
+ (gdb) target remote the-target:2345
+
+ communicates via a TCP connection to port 2345 on host
+ `the-target'. For TCP connections, you must start up `gdbserver'
+ prior to using the `target remote' command. Otherwise you may get
+ an error whose text depends on the host system, but which usually
+ looks something like `Connection refused'.
+
+ ---------- Footnotes ----------
+
+ (1) If you choose a port number that conflicts with another
+service, `gdbserver' prints an error message and exits.
+
+
+File: gdb.info, Node: i960-Nindy Remote, Next: UDI29K Remote, Prev: Remote Serial, Up: Remote
+
+GDB with a remote i960 (Nindy)
+------------------------------
+
+ "Nindy" is a ROM Monitor program for Intel 960 target systems. When
+GDB is configured to control a remote Intel 960 using Nindy, you can
+tell GDB how to connect to the 960 in several ways:
+
+ * Through command line options specifying serial port, version of the
+ Nindy protocol, and communications speed;
+
+ * By responding to a prompt on startup;
+
+ * By using the `target' command at any point during your GDB
+ session. *Note Commands for managing targets: Target Commands.
+
+* Menu:
+
+* Nindy Startup:: Startup with Nindy
+* Nindy Options:: Options for Nindy
+* Nindy Reset:: Nindy reset command
+
+
+File: gdb.info, Node: Nindy Startup, Next: Nindy Options, Up: i960-Nindy Remote
+
+Startup with Nindy
+------------------
+
+ If you simply start `gdb' without using any command-line options,
+you are prompted for what serial port to use, *before* you reach the
+ordinary GDB prompt:
+
+ Attach /dev/ttyNN -- specify NN, or "quit" to quit:
+
+Respond to the prompt with whatever suffix (after `/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 `target' (*note Commands for managing targets: Target Commands.).
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-6 b/gnu/usr.bin/gdb/doc/gdb.info-6
new file mode 100644
index 0000000..8a746fd
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-6
@@ -0,0 +1,1220 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ 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.
+
+ 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.
+
+
+File: gdb.info, Node: Nindy Options, Next: Nindy Reset, Prev: Nindy Startup, Up: i960-Nindy Remote
+
+Options for Nindy
+-----------------
+
+ These are the startup options for beginning your GDB session with a
+Nindy-960 board attached:
+
+`-r 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
+ GDB is configured for the Intel 960 target architecture. You may
+ specify PORT as any of: a full pathname (e.g. `-r /dev/ttya'), a
+ device name in `/dev' (e.g. `-r ttya'), or simply the unique
+ suffix for a specific `tty' (e.g. `-r a').
+
+`-O'
+ (An uppercase letter "O", not a zero.) Specify that GDB should use
+ the "old" Nindy monitor protocol to connect to the target system.
+ This option is only available when GDB is configured for the Intel
+ 960 target architecture.
+
+ *Warning:* if you specify `-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. GDB
+ repeatedly attempts to reconnect at several different line
+ speeds. You can abort this process with an interrupt.
+
+`-brk'
+ Specify that GDB should first send a `BREAK' signal to the target
+ system, in an attempt to reset it, before connecting to a Nindy
+ target.
+
+ *Warning:* Many target systems do not have the hardware that
+ this requires; it only works with a few boards.
+
+ The standard `-b' option controls the line speed used on the serial
+port.
+
+
+File: gdb.info, Node: Nindy Reset, Prev: Nindy Options, Up: i960-Nindy Remote
+
+Nindy reset command
+-------------------
+
+`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.
+
+
+File: gdb.info, Node: UDI29K Remote, Next: EB29K Remote, Prev: i960-Nindy Remote, Up: Remote
+
+GDB and the UDI protocol for AMD29K
+-----------------------------------
+
+ GDB 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 `MONTIP',
+available from AMD at no charge. You can also use GDB with the UDI
+conformant a29k simulator program `ISSTIP', also available from AMD.
+
+`target udi KEYWORD'
+ Select the UDI interface to a remote a29k board or simulator, where
+ KEYWORD is an entry in the AMD configuration file `udi_soc'. This
+ file contains keyword entries which specify parameters used to
+ connect to a29k targets. If the `udi_soc' file is not in your
+ working directory, you must set the environment variable `UDICONF'
+ to its pathname.
+
+
+File: gdb.info, Node: EB29K Remote, Next: VxWorks Remote, Prev: UDI29K Remote, Up: Remote
+
+GDB and the EBMON protocol for AMD29K
+-------------------------------------
+
+ AMD distributes a 29K development board meant to fit in a PC,
+together with a DOS-hosted monitor program called `EBMON'. As a
+shorthand term, this development system is called the "EB29K". To use
+GDB 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 `COM1' port and
+`/dev/ttya' on the Unix system.
+
+* Menu:
+
+* Comms (EB29K):: Communications setup
+* gdb-EB29K:: EB29K cross-debugging
+* Remote Log:: Remote log
+
+
+File: gdb.info, Node: Comms (EB29K), Next: gdb-EB29K, Up: EB29K Remote
+
+Communications setup
+--------------------
+
+ The next step is to set up the PC's port, by doing something like
+this in DOS on the PC:
+
+ C:\> MODE com1:9600,n,8,1,none
+
+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.
+
+ To give control of the PC to the Unix side of the serial line, type
+the following at the DOS console:
+
+ C:\> CTTY com1
+
+(Later, if you wish to return control to the DOS console, you can use
+the command `CTTY con'--but you must send it over the device that had
+control, in our example over the `COM1' serial line).
+
+ From the Unix host, use a communications program such as `tip' or
+`cu' to communicate with the PC; for example,
+
+ cu -s 9600 -l /dev/ttya
+
+The `cu' options shown specify, respectively, the linespeed and the
+serial port to use. If you use `tip' instead, your command line may
+look something like the following:
+
+ tip -9600 /dev/ttya
+
+Your system may require a different name where we show `/dev/ttya' as
+the argument to `tip'. The communications parameters, including which
+port to use, are associated with the `tip' argument in the "remote"
+descriptions file--normally the system table `/etc/remote'.
+
+ Using the `tip' or `cu' connection, change the DOS working directory
+to the directory containing a copy of your 29K program, then start the
+PC program `EBMON' (an EB29K control program supplied with your board
+by AMD). You should see an initial display from `EBMON' similar to the
+one that follows, ending with the `EBMON' prompt `#'--
+
+ 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
+
+ # ~.
+
+ Then exit the `cu' or `tip' program (done in the example by typing
+`~.' at the `EBMON' prompt). `EBMON' will keep running, ready for GDB
+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 `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; GDB will *not* download it over the serial line.
+
+
+File: gdb.info, Node: gdb-EB29K, Next: Remote Log, Prev: Comms (EB29K), Up: EB29K Remote
+
+EB29K cross-debugging
+---------------------
+
+ Finally, `cd' to the directory containing an image of your 29K
+program on the Unix system, and start GDB--specifying as argument the
+name of your 29K program:
+
+ cd /usr/joe/work29k
+ gdb myfoo
+
+ Now you can use the `target' command:
+
+ target amd-eb /dev/ttya 9600 MYFOO
+
+In this example, we've assumed your program is in a file called
+`myfoo'. Note that the filename given as the last argument to `target
+amd-eb' should be the name of the program as it appears to DOS. In our
+example this is simply `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 GDB command
+`run'.
+
+ To stop debugging the remote program, use the GDB `detach' command.
+
+ To return control of the PC to its console, use `tip' or `cu' once
+again, after your GDB session has concluded, to attach to `EBMON'. You
+can then type the command `q' to shut down `EBMON', returning control
+to the DOS command-line interpreter. Type `CTTY con' to return command
+input to the main DOS console, and type `~.' to leave `tip' or `cu'.
+
+
+File: gdb.info, Node: Remote Log, Prev: gdb-EB29K, Up: EB29K Remote
+
+Remote log
+----------
+
+ The `target amd-eb' command creates a file `eb.log' in the current
+working directory, to help debug problems with the connection.
+`eb.log' records all the output from `EBMON', including echoes of the
+commands sent to it. Running `tail -f' on this file in another window
+often helps to understand trouble with `EBMON', or unexpected events on
+the PC side of the connection.
+
+
+File: gdb.info, Node: ST2000 Remote, Next: Hitachi Remote, Prev: VxWorks Remote, Up: Remote
+
+GDB 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
+
+ target st2000 DEV SPEED
+
+to establish it as your debugging environment. DEV is normally the
+name of a serial device, such as `/dev/ttya', connected to the ST2000
+via a serial line. You can instead specify DEV as a TCP connection
+(for example, to a serial line attached via a terminal concentrator)
+using the syntax `HOSTNAME:PORTNUMBER'.
+
+ The `load' and `attach' commands are *not* defined for this target;
+you must load your program into the ST2000 as you normally would for
+standalone operation. GDB will read debugging information (such as
+symbols) from a separate, debugging version of the program available on
+your host computer.
+
+ These auxiliary GDB commands are available to help you with the
+ST2000 environment:
+
+`st2000 COMMAND'
+ Send a COMMAND to the STDBUG monitor. See the manufacturer's
+ manual for available commands.
+
+`connect'
+ Connect the controlling terminal to the STDBUG command monitor.
+ When you are done interacting with STDBUG, typing either of two
+ character sequences will get you back to the GDB command prompt:
+ `RET~.' (Return, followed by tilde and period) or `RET~C-d'
+ (Return, followed by tilde and control-D).
+
+
+File: gdb.info, Node: VxWorks Remote, Next: ST2000 Remote, Prev: EB29K Remote, Up: Remote
+
+GDB and VxWorks
+---------------
+
+ GDB 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. GDB uses code that runs on
+both the Unix host and on the VxWorks target. The program `gdb' is
+installed and executed on the Unix host. (It may be installed with the
+name `vxgdb', to distinguish it from a GDB 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.
+
+ The remote debugging interface (RDB) routines are installed and
+executed on the VxWorks target. These routines are included in the
+VxWorks library `rdb.a' and are incorporated into the system image when
+source-level debugging is enabled in the VxWorks configuration.
+
+ If you wish, you can define `INCLUDE_RDB' in the VxWorks
+configuration file `configAll.h' to include the RDB interface routines
+and spawn the source debugging task `tRdbTask' when VxWorks is booted.
+For more information on configuring and remaking VxWorks, see the
+manufacturer's manual.
+
+ Once you have included the RDB interface in your VxWorks system image
+and set your Unix execution search path to find GDB, you are ready to
+run GDB. From your Unix host, run `gdb' (or `vxgdb', depending on your
+installation).
+
+ GDB comes up showing the prompt:
+
+ (vxgdb)
+
+* Menu:
+
+* VxWorks Connection:: Connecting to VxWorks
+* VxWorks Download:: VxWorks download
+* VxWorks Attach:: Running tasks
+
+
+File: gdb.info, Node: VxWorks Connection, Next: VxWorks Download, Up: VxWorks Remote
+
+Connecting to VxWorks
+---------------------
+
+ The GDB command `target' lets you connect to a VxWorks target on the
+network. To connect to a target whose host name is "`tt'", type:
+
+ (vxgdb) target vxworks tt
+
+ GDB displays messages like these:
+
+ Attaching remote machine across net...
+ Connected to tt.
+
+ GDB then attempts to read the symbol tables of any object modules
+loaded into the VxWorks target since it was last booted. GDB locates
+these files by searching the directories listed in the command search
+path (*note Your program's environment: Environment.); if it fails to
+find an object file, it displays a message such as:
+
+ prog.o: No such file or directory.
+
+ When this happens, add the appropriate directory to the search path
+with the GDB command `path', and execute the `target' command again.
+
+
+File: gdb.info, Node: VxWorks Download, Next: VxWorks Attach, Prev: VxWorks Connection, Up: VxWorks Remote
+
+VxWorks download
+----------------
+
+ 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 GDB `load' command
+to download a file from Unix to VxWorks incrementally. The object file
+given as an argument to the `load' command is actually opened twice:
+first by the VxWorks target in order to download the code, then by GDB
+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 `prog.o' may reside in `VXPATH/vw/demo/rdb' in
+VxWorks and in `HOSTPATH/vw/demo/rdb' on the host. To load this
+program, type this on VxWorks:
+
+ -> cd "VXPATH/vw/demo/rdb"
+
+ Then, in GDB, type:
+
+ (vxgdb) cd HOSTPATH/vw/demo/rdb
+ (vxgdb) load prog.o
+
+ GDB displays a response similar to this:
+
+ Reading symbol data from wherever/vw/demo/rdb/prog.o... done.
+
+ You can also use the `load' command to reload an object module after
+editing and recompiling the corresponding source file. Note that this
+will cause GDB to 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.)
+
+
+File: gdb.info, Node: VxWorks Attach, Prev: VxWorks Download, Up: VxWorks Remote
+
+Running tasks
+-------------
+
+ You can also attach to an existing task using the `attach' command as
+follows:
+
+ (vxgdb) attach TASK
+
+where TASK is the VxWorks hexadecimal task ID. The task can be running
+or suspended when you attach to it. If running, it will be suspended at
+the time of attachment.
+
+
+File: gdb.info, Node: Hitachi Remote, Next: MIPS Remote, Prev: ST2000 Remote, Up: Remote
+
+GDB and Hitachi Microprocessors
+-------------------------------
+
+ GDB needs to know these things to talk to your Hitachi SH, H8/300,
+or H8/500:
+
+ 1. that you want to use `target hms', the remote debugging interface
+ for Hitachi microprocessors (this is the default when GDB is
+ configured specifically for the Hitachi SH, H8/300, or H8/500);
+
+ 2. what serial device connects your host to your Hitachi board (the
+ first serial device available on your host is the default);
+
+
+ Use the special `gdb' command `device PORT' if you need to
+explicitly set the serial device. The default PORT is the first
+available port on your host. This is only necessary on Unix hosts,
+where it is typically something like `/dev/ttya'.
+
+ `gdb' has another special command to set the communications speed:
+`speed 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 `mode'
+command (for instance, `mode com2:9600,n,8,1,p' for a 9600 bps
+connection).
+
+ The `device' and `speed' commands are available only when you use a
+Unix host to debug your Hitachi microprocessor programs. If you use a
+DOS host, GDB depends on an auxiliary terminate-and-stay-resident
+program called `asynctsr' to communicate with the development board
+through a PC serial port. You must also use the DOS `mode' command to
+set up the serial port on the DOS side.
+
+
+File: gdb.info, Node: MIPS Remote, Next: Simulator, Prev: Hitachi Remote, Up: Remote
+
+GDB and remote MIPS boards
+--------------------------
+
+ GDB can use the MIPS remote debugging protocol to talk to a MIPS
+board attached to a serial line. This is available when you configure
+GDB with `--target=mips-idt-ecoff'.
+
+ To run a program on the board, start up `gdb' with the name of your
+program as the argument. To connect to the board, use the command
+`target mips PORT', where 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 `load' command to download it. You can then use
+all the usual GDB commands.
+
+ You can also specify PORT as a TCP connection (for instance, to a
+serial line managed by a terminal concentrator), using the syntax
+`HOSTNAME:PORTNUMBER'.
+
+ You can see some debugging information about communications with the
+board by setting the `remotedebug' variable. If you set it to 1 using
+`set remotedebug 1' every packet will be displayed. If you set it to 2
+every character will be displayed. You can check the current value at
+any time with the command `show remotedebug'.
+
+ You can control the timeout used while waiting for a packet, in the
+MIPS remote protocol, with the `set timeout SECONDS' command. The
+default is 5 seconds. Similarly, you can control the timeout used while
+waiting for an acknowledgement of a packet with the `set
+retransmit-timeout SECONDS' command. The default is 3 seconds. You
+can inspect both values with `show timeout' and `show
+retransmit-timeout'. (These commands are *only* available when GDB is
+configured for `--target=mips-idt-ecoff'.)
+
+ If your target board does not support the MIPS floating point
+coprocessor, you should use the command `set mipsfpu off' (you may wish
+to put this in your .gdbinit file). This tells GDB how to find the
+return value of functions which return floating point values. It also
+allows GDB to avoid saving the floating point registers when calling
+functions on the board.
+
+
+File: gdb.info, Node: Simulator, Prev: MIPS Remote, Up: Remote
+
+Simulated CPU target
+--------------------
+
+ For some configurations, GDB includes a CPU simulator that you can
+use instead of a hardware CPU to debug your programs. Currently, a
+simulator is available when GDB is configured to debug Zilog Z8000 or
+Hitachi microprocessor targets.
+
+ For the Z8000 family, `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.
+
+`target sim'
+ Debug programs on a simulated CPU (which CPU depends on the GDB
+ configuration)
+
+After specifying this target, you can debug programs for the simulated
+CPU in the same style as programs for your host computer; use the
+`file' command to load a new program image, the `run' command to run
+your program, and so on.
+
+ As well as making available all the usual machine registers (see
+`info reg'), this debugging target provides three additional items of
+information as specially named registers:
+
+`cycles'
+ Counts clock-ticks in the simulator.
+
+`insts'
+ Counts instructions run in the simulator.
+
+`time'
+ Execution time in 60ths of a second.
+
+ You can refer to these values in GDB expressions with the usual
+conventions; for example, `b fputc if $cycles>5000' sets a conditional
+breakpoint that will suspend only after at least 5000 simulated clock
+ticks.
+
+
+File: gdb.info, Node: Controlling GDB, Next: Sequences, Prev: Targets, Up: Top
+
+Controlling GDB
+***************
+
+ You can alter the way GDB interacts with you by using the `set'
+command. For commands controlling how GDB displays data, *note 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
+
+
+File: gdb.info, Node: Prompt, Next: Editing, Up: Controlling GDB
+
+Prompt
+======
+
+ GDB indicates its readiness to read a command by printing a string
+called the "prompt". This string is normally `(gdb)'. You can change
+the prompt string with the `set prompt' command. For instance, when
+debugging GDB with GDB, it is useful to change the prompt in one of the
+GDB sessions so that you can always tell which one you are talking to.
+
+`set prompt NEWPROMPT'
+ Directs GDB to use NEWPROMPT as its prompt string henceforth.
+
+`show prompt'
+ Prints a line of the form: `Gdb's prompt is: YOUR-PROMPT'
+
+
+File: gdb.info, Node: Editing, Next: History, Prev: Prompt, Up: Controlling GDB
+
+Command editing
+===============
+
+ GDB reads its input commands via the "readline" interface. This GNU
+library provides consistent behavior for programs which provide a
+command line interface to the user. Advantages are `emacs'-style or
+`vi'-style inline editing of commands, `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 GDB with the
+command `set'.
+
+`set editing'
+`set editing on'
+ Enable command line editing (enabled by default).
+
+`set editing off'
+ Disable command line editing.
+
+`show editing'
+ Show whether command line editing is enabled.
+
+
+File: gdb.info, Node: History, Next: Screen Size, Prev: Editing, Up: Controlling GDB
+
+Command history
+===============
+
+ GDB 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 GDB command history facility.
+
+`set history filename FNAME'
+ Set the name of the GDB command history file to FNAME. This is
+ the file from which GDB will read an initial command history list
+ or to which it will write this list when it exits. This list is
+ accessed through history expansion or through the history command
+ editing characters listed below. This file defaults to the value
+ of the environment variable `GDBHISTFILE', or to `./.gdb_history'
+ if this variable is not set.
+
+`set history save'
+`set history save on'
+ Record command history in a file, whose name may be specified with
+ the `set history filename' command. By default, this option is
+ disabled.
+
+`set history save off'
+ Stop recording command history in a file.
+
+`set history size SIZE'
+ Set the number of commands which GDB will keep in its history list.
+ This defaults to the value of the environment variable `HISTSIZE',
+ or to 256 if this variable is not set.
+
+ History expansion assigns special meaning to the character `!'.
+
+ Since `!' is also the logical not operator in C, history expansion
+is off by default. If you decide to enable history expansion with the
+`set history expansion on' command, you may sometimes need to follow
+`!' (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 will not attempt substitution on the strings `!=' and `!(',
+even when history expansion is enabled.
+
+ The commands to control history expansion are:
+
+`set history expansion on'
+`set history expansion'
+ Enable history expansion. History expansion is off by default.
+
+`set history expansion off'
+ Disable history expansion.
+
+ The readline code comes with more complete documentation of
+ editing and history expansion features. Users unfamiliar with
+ `emacs' or `vi' may wish to read it.
+
+`show history'
+`show history filename'
+`show history save'
+`show history size'
+`show history expansion'
+ These commands display the state of the GDB history parameters.
+ `show history' by itself displays all four states.
+
+`show commands'
+ Display the last ten commands in the command history.
+
+`show commands N'
+ Print ten commands centered on command number N.
+
+`show commands +'
+ Print ten commands just after the commands last printed.
+
+
+File: gdb.info, Node: Screen Size, Next: Numbers, Prev: History, Up: Controlling GDB
+
+Screen size
+===========
+
+ Certain commands to GDB may produce large amounts of information
+output to the screen. To help you read all of it, GDB pauses and asks
+you for input at the end of each page of output. Type RET when you
+want to continue the output, or `q' to discard the remaining output.
+Also, the screen width setting determines when to wrap lines of output.
+Depending on what is being printed, GDB tries to break the line at a
+readable place, rather than simply letting it overflow onto the
+following line.
+
+ Normally GDB knows the size of the screen from the termcap data base
+together with the value of the `TERM' environment variable and the
+`stty rows' and `stty cols' settings. If this is not correct, you can
+override it with the `set height' and `set width' commands:
+
+`set height LPP'
+`show height'
+`set width CPL'
+`show width'
+ These `set' commands specify a screen height of LPP lines and a
+ screen width of CPL characters. The associated `show' commands
+ display the current settings.
+
+ If you specify a height of zero lines, GDB will 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 `set width 0' to prevent GDB from
+ wrapping its output.
+
+
+File: gdb.info, Node: Numbers, Next: Messages/Warnings, Prev: Screen Size, Up: Controlling GDB
+
+Numbers
+=======
+
+ You can always enter numbers in octal, decimal, or hexadecimal in
+GDB by the usual conventions: octal numbers begin with `0', decimal
+numbers end with `.', and hexadecimal numbers begin with `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 `set radix' command.
+
+`set radix BASE'
+ Set the default base for numeric input and display. Supported
+ choices for BASE are decimal 8, 10, or 16. BASE must itself be
+ specified either unambiguously or using the current default radix;
+ for example, any of
+
+ set radix 012
+ set radix 10.
+ set radix 0xa
+
+ will set the base to decimal. On the other hand, `set radix 10'
+ will leave the radix unchanged no matter what it was.
+
+`show radix'
+ Display the current default base for numeric input and display.
+
+
+File: gdb.info, Node: Messages/Warnings, Prev: Numbers, Up: Controlling GDB
+
+Optional warnings and messages
+==============================
+
+ By default, GDB is silent about its inner workings. If you are
+running on a slow machine, you may want to use the `set verbose'
+command. It will make GDB tell you when it does a lengthy internal
+operation, so you will not think it has crashed.
+
+ Currently, the messages controlled by `set verbose' are those which
+announce that the symbol table for a source file is being read; see
+`symbol-file' in *Note Commands to specify files: Files.
+
+`set verbose on'
+ Enables GDB output of certain informational messages.
+
+`set verbose off'
+ Disables GDB output of certain informational messages.
+
+`show verbose'
+ Displays whether `set verbose' is on or off.
+
+ By default, if GDB 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 (*note Errors reading symbol files: Symbol
+Errors.).
+
+`set complaints LIMIT'
+ Permits GDB to output LIMIT complaints about each type of unusual
+ symbols before becoming silent about the problem. Set LIMIT to
+ zero to suppress all complaints; set it to a large number to
+ prevent complaints from being suppressed.
+
+`show complaints'
+ Displays how many symbol complaints GDB is permitted to produce.
+
+ By default, GDB 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:
+
+ (gdb) run
+ The program being debugged has been started already.
+ Start it from the beginning? (y or n)
+
+ If you are willing to unflinchingly face the consequences of your own
+commands, you can disable this "feature":
+
+`set confirm off'
+ Disables confirmation requests.
+
+`set confirm on'
+ Enables confirmation requests (the default).
+
+`show confirm'
+ Displays state of confirmation requests.
+
+ Some systems allow individual object files that make up your program
+to be replaced without stopping and restarting your program. For
+example, in VxWorks you can simply recompile a defective object file
+and keep on running. If you are running on one of these systems, you
+can allow GDB to reload the symbols for automatically relinked modules:
+
+`set symbol-reloading on'
+ Replace symbol definitions for the corresponding source file when
+ an object file with a particular name is seen again.
+
+`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 `symbol-reloading' off, since otherwise GDB may
+ discard symbols when linking large programs, that may contain
+ several modules (from different directories or libraries) with the
+ same name.
+
+`show symbol-reloading'
+ Show the current `on' or `off' setting.
+
+
+File: gdb.info, Node: Sequences, Next: Emacs, Prev: Controlling GDB, Up: Top
+
+Canned Sequences of Commands
+****************************
+
+ Aside from breakpoint commands (*note Breakpoint command lists:
+Break Commands.), GDB 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
+
+
+File: gdb.info, Node: Define, Next: Hooks, Up: Sequences
+
+User-defined commands
+=====================
+
+ A "user-defined command" is a sequence of GDB commands to which you
+assign a new name as a command. This is done with the `define' command.
+
+`define COMMANDNAME'
+ Define a command named 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 GDB command
+ lines, which are given following the `define' command. The end of
+ these commands is marked by a line containing `end'.
+
+`document COMMANDNAME'
+ Give documentation to the user-defined command COMMANDNAME. The
+ command COMMANDNAME must already be defined. This command reads
+ lines of documentation just as `define' reads the lines of the
+ command definition, ending with `end'. After the `document'
+ command is finished, `help' on command COMMANDNAME will print the
+ documentation you have specified.
+
+ You may use the `document' command again to change the
+ documentation of a command. Redefining the command with `define'
+ does not change the documentation.
+
+`help user-defined'
+ List all user-defined commands, with the first line of the
+ documentation (if any) for each.
+
+`show user'
+`show user COMMANDNAME'
+ Display the GDB commands used to define COMMANDNAME (but not its
+ documentation). If no COMMANDNAME is given, display the
+ definitions for all user-defined commands.
+
+ 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
+GDB commands that normally print messages to say what they are doing
+omit the messages when used in a user-defined command.
+
+
+File: gdb.info, Node: Hooks, Next: Command Files, Prev: Define, Up: Sequences
+
+User-defined command hooks
+==========================
+
+ You may define *hooks*, which are a special kind of user-defined
+command. Whenever you run the command `foo', if the user-defined
+command `hook-foo' exists, it is executed (with no arguments) before
+that command.
+
+ In addition, a pseudo-command, `stop' exists. Defining
+(`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.
+
+ For example, to ignore `SIGALRM' signals while single-stepping, but
+treat them normally during normal execution, you could define:
+
+ define hook-stop
+ handle SIGALRM nopass
+ end
+
+ define hook-run
+ handle SIGALRM pass
+ end
+
+ define hook-continue
+ handle SIGLARM pass
+ end
+
+ You can define a hook for any single-word command in GDB, but not
+for command aliases; you should define a hook for the basic command
+name, e.g. `backtrace' rather than `bt'. If an error occurs during
+the execution of your hook, execution of GDB commands stops and GDB
+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 will get a warning from the `define' command.
+
+
+File: gdb.info, Node: Command Files, Next: Output, Prev: Hooks, Up: Sequences
+
+Command files
+=============
+
+ A command file for GDB is a file of lines that are GDB commands.
+Comments (lines starting with `#') 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.
+
+ When you start GDB, it automatically executes commands from its
+"init files". These are files named `.gdbinit'. GDB reads the init
+file (if any) in your home directory and then the init file (if any) in
+the current working directory. (The init files are not executed if you
+use the `-nx' option; *note Choosing modes: Mode Options..)
+
+ On some configurations of GDB, 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:
+
+ * VxWorks (Wind River Systems real-time OS): `.vxgdbinit'
+
+ * OS68K (Enea Data Systems real-time OS): `.os68gdbinit'
+
+ * ES-1800 (Ericsson Telecom AB M68000 emulator): `.esgdbinit'
+
+ You can also request the execution of a command file with the
+`source' command:
+
+`source FILENAME'
+ Execute the command file FILENAME.
+
+ 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 GDB commands
+that normally print messages to say what they are doing omit the
+messages when called from command files.
+
+
+File: gdb.info, Node: Output, Prev: Command Files, Up: Sequences
+
+Commands for controlled output
+==============================
+
+ During the execution of a command file or a user-defined command,
+normal GDB 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.
+
+`echo TEXT'
+ Print TEXT. Nonprinting characters can be included in TEXT using
+ C escape sequences, such as `\n' to print a newline. *No newline
+ will be 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 ` and
+ foo = ', use the command `echo \ and foo = \ '.
+
+ A backslash at the end of TEXT can be used, as in C, to continue
+ the command onto subsequent lines. For example,
+
+ echo This is some text\n\
+ which is continued\n\
+ onto several lines.\n
+
+ produces the same output as
+
+ echo This is some text\n
+ echo which is continued\n
+ echo onto several lines.\n
+
+`output EXPRESSION'
+ Print the value of EXPRESSION and nothing but that value: no
+ newlines, no `$NN = '. The value is not entered in the value
+ history either. *Note Expressions: Expressions, for more
+ information on expressions.
+
+`output/FMT EXPRESSION'
+ Print the value of EXPRESSION in format FMT. You can use the same
+ formats as for `print'. *Note Output formats: Output Formats, for
+ more information.
+
+`printf STRING, EXPRESSIONS...'
+ Print the values of the EXPRESSIONS under the control of STRING.
+ The EXPRESSIONS are separated by commas and may be either numbers
+ or pointers. Their values are printed as specified by STRING,
+ exactly as if your program were to execute the C subroutine
+
+ printf (STRING, EXPRESSIONS...);
+
+ For example, you can print two values in hex like this:
+
+ printf "foo, bar-foo = 0x%x, 0x%x\n", foo, bar-foo
+
+ 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.
+
+
+File: gdb.info, Node: Emacs, Next: GDB Bugs, Prev: Sequences, Up: Top
+
+Using GDB under GNU Emacs
+*************************
+
+ A special interface allows you to use GNU Emacs to view (and edit)
+the source files for the program you are debugging with GDB.
+
+ To use this interface, use the command `M-x gdb' in Emacs. Give the
+executable file you want to debug as an argument. This command starts
+GDB as a subprocess of Emacs, with input and output through a newly
+created Emacs buffer.
+
+ Using GDB under Emacs is just like using GDB normally except for two
+things:
+
+ * All "terminal" input and output goes through the Emacs buffer.
+
+ This applies both to GDB 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, `C-c C-c' for an interrupt, `C-c C-z' for a stop.
+
+ * GDB displays source code through Emacs.
+
+ Each time GDB displays a stack frame, Emacs automatically finds the
+source file for that frame and puts an arrow (`=>') at the left margin
+of the current line. Emacs uses a separate buffer for source display,
+and splits the screen to show both your GDB session and the source.
+
+ Explicit GDB `list' or search commands still produce output as
+usual, but you probably will have no reason to use them.
+
+ *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 will not appear to show your source. GDB can find programs
+ by searching your environment's `PATH' variable, so the GDB input
+ and output session will proceed normally; but Emacs does not get
+ enough information back from GDB to locate the source files in
+ this situation. To avoid this problem, either start GDB mode from
+ the directory where your program resides, or specify a full path
+ name when prompted for the `M-x gdb' argument.
+
+ A similar confusion can result if you use the GDB `file' command to
+ switch to debugging a program in some other location, from an
+ existing GDB buffer in Emacs.
+
+ By default, `M-x gdb' calls the program called `gdb'. If you need
+to call GDB by a different name (for example, if you keep several
+configurations around, with different names) you can set the Emacs
+variable `gdb-command-name'; for example,
+
+ (setq gdb-command-name "mygdb")
+
+(preceded by `ESC ESC', or typed in the `*scratch*' buffer, or in your
+`.emacs' file) will make Emacs call the program named "`mygdb'" instead.
+
+ In the GDB I/O buffer, you can use these special Emacs commands in
+addition to the standard Shell mode commands:
+
+`C-h m'
+ Describe the features of Emacs' GDB Mode.
+
+`M-s'
+ Execute to another source line, like the GDB `step' command; also
+ update the display window to show the current file and location.
+
+`M-n'
+ Execute to next source line in this function, skipping all function
+ calls, like the GDB `next' command. Then update the display window
+ to show the current file and location.
+
+`M-i'
+ Execute one instruction, like the GDB `stepi' command; update
+ display window accordingly.
+
+`M-x gdb-nexti'
+ Execute to next instruction, using the GDB `nexti' command; update
+ display window accordingly.
+
+`C-c C-f'
+ Execute until exit from the selected stack frame, like the GDB
+ `finish' command.
+
+`M-c'
+ Continue execution of your program, like the GDB `continue'
+ command.
+
+ *Warning:* In Emacs v19, this command is `C-c C-p'.
+
+`M-u'
+ Go up the number of frames indicated by the numeric argument
+ (*note Numeric Arguments: (emacs)Arguments.), like the GDB `up'
+ command.
+
+ *Warning:* In Emacs v19, this command is `C-c C-u'.
+
+`M-d'
+ Go down the number of frames indicated by the numeric argument,
+ like the GDB `down' command.
+
+ *Warning:* In Emacs v19, this command is `C-c C-d'.
+
+`C-x &'
+ Read the number where the cursor is positioned, and insert it at
+ the end of the GDB I/O buffer. For example, if you wish to
+ disassemble code around an address that was displayed earlier,
+ type `disassemble'; then move the cursor to the address display,
+ and pick up the argument for `disassemble' by typing `C-x &'.
+
+ You can customize this further by defining elements of the list
+ `gdb-print-command'; once it is defined, you can format or
+ otherwise process numbers picked up by `C-x &' before they are
+ inserted. A numeric argument to `C-x &' will both indicate that
+ you wish special formatting, and act 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 `format';
+ otherwise the number is passed as an argument to the corresponding
+ list element.
+
+ In any source file, the Emacs command `C-x SPC' (`gdb-break') tells
+GDB 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 `f' in the GDB buffer, to request a
+frame display; when you run under Emacs, this will recreate 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 GDB
+communicates with Emacs in terms of line numbers. If you add or delete
+lines from the text, the line numbers that GDB knows will cease to
+correspond properly with the code.
+
+
+File: gdb.info, Node: GDB Bugs, Next: Command Line Editing, Prev: Emacs, Up: Top
+
+Reporting Bugs in GDB
+*********************
+
+ Your bug reports play an essential role in making GDB 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 GDB work
+better. Bug reports are your contribution to the maintenance of GDB.
+
+ 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
+
+
+File: gdb.info, Node: Bug Criteria, Next: Bug Reporting, Up: GDB Bugs
+
+Have you found a bug?
+=====================
+
+ If you are not sure whether you have found a bug, here are some
+guidelines:
+
+ * If the debugger gets a fatal signal, for any input whatever, that
+ is a GDB bug. Reliable debuggers never crash.
+
+ * If GDB produces an error message for valid input, that is a bug.
+
+ * If GDB 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".
+
+ * If you are an experienced user of debugging tools, your suggestions
+ for improvement of GDB are welcome in any case.
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-7 b/gnu/usr.bin/gdb/doc/gdb.info-7
new file mode 100644
index 0000000..963527e
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-7
@@ -0,0 +1,1233 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ 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.
+
+ 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.
+
+
+File: gdb.info, Node: Bug Reporting, Prev: Bug Criteria, Up: GDB Bugs
+
+How to report bugs
+==================
+
+ A number of companies and individuals offer support for GNU products.
+If you obtained GDB 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 `etc/SERVICE' in the GNU Emacs distribution.
+
+ In any event, we also recommend that you send bug reports for GDB to
+one of these addresses:
+
+ bug-gdb@prep.ai.mit.edu
+ {ucbvax|mit-eddie|uunet}!prep.ai.mit.edu!bug-gdb
+
+ *Do not send bug reports to `info-gdb', or to `help-gdb', or to any
+newsgroups.* Most users of GDB do not want to receive bug reports.
+Those that do, have arranged to receive `bug-gdb'.
+
+ The mailing list `bug-gdb' has a newsgroup `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:
+
+ GNU Debugger Bugs
+ Free Software Foundation
+ 545 Tech Square
+ Cambridge, MA 02139
+
+ The fundamental principle of reporting bugs usefully is this:
+*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 *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:
+
+ * The version of GDB. GDB announces it if you start with no
+ arguments; you can also print it at any time using `show version'.
+
+ Without this, we will not know whether there is any point in
+ looking for the bug in the current version of GDB.
+
+ * The type of machine you are using, and the operating system name
+ and version number.
+
+ * What compiler (and its version) was used to compile GDB--e.g.
+ "gcc-2.0".
+
+ * What compiler (and its version) was used to compile the program you
+ are debugging--e.g. "gcc-2.0".
+
+ * The command arguments you gave the compiler to compile your
+ example and observe the bug. For example, did you use `-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.
+
+ * A complete input script, and all necessary source files, that will
+ reproduce the bug.
+
+ * 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 GDB 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 GDB 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.
+
+ * If you wish to suggest changes to the GDB source, send us context
+ diffs. If you even discuss something in the GDB 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.
+
+ Here are some things that are not necessary:
+
+ * 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 *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, etc.
+
+ 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.
+
+ * 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 GDB 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.
+
+ * 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.
+
+
+File: gdb.info, Node: Command Line Editing, Next: Using History Interactively, Prev: GDB Bugs, Up: Top
+
+Command Line Editing
+********************
+
+ This text describes GNU's command line editing interface.
+
+* Menu:
+
+* Introduction and Notation:: Notation used in this text.
+* Readline Interaction:: The minimum set of commands for editing a line.
+* Readline Init File:: Customizing Readline from a user's view.
+
+
+File: gdb.info, Node: Introduction and Notation, Next: Readline Interaction, Up: Command Line Editing
+
+Introduction to Line Editing
+============================
+
+ The following paragraphs describe the notation we use to represent
+keystrokes.
+
+ The text C-k is read as `Control-K' and describes the character
+produced when the Control key is depressed and the k key is struck.
+
+ The text M-k is read as `Meta-K' and describes the character
+produced when the meta key (if you have one) is depressed, and the k
+key is struck. If you do not have a meta key, the identical keystroke
+can be generated by typing ESC first, and then typing k. Either
+process is known as "metafying" the k key.
+
+ The text M-C-k is read as `Meta-Control-k' and describes the
+character produced by "metafying" C-k.
+
+ In addition, several keys have their own names. Specifically, DEL,
+ESC, LFD, SPC, RET, and TAB all stand for themselves when seen in this
+text, or in an init file (*note Readline Init File::., for more info).
+
+
+File: gdb.info, Node: Readline Interaction, Next: Readline Init File, Prev: Introduction and Notation, Up: Command Line Editing
+
+Readline Interaction
+====================
+
+ Often during an interactive session you type in a long line of text,
+only to notice that the first word on the line is misspelled. The
+Readline library gives you a set of commands for manipulating the text
+as you type it in, allowing you to just fix your typo, and not forcing
+you to retype the majority of the line. Using these editing commands,
+you move the cursor to the place that needs correction, and delete or
+insert the text of the corrections. Then, when you are satisfied with
+the line, you simply press RETURN. You do not have to be at the end of
+the line to press RETURN; the entire line is accepted regardless of the
+location of the cursor within the line.
+
+* Menu:
+
+* Readline Bare Essentials:: The least you need to know about Readline.
+* Readline Movement Commands:: Moving about the input line.
+* Readline Killing Commands:: How to delete text, and how to get it back!
+* Readline Arguments:: Giving numeric arguments to commands.
+
+
+File: gdb.info, Node: Readline Bare Essentials, Next: Readline Movement Commands, Up: Readline Interaction
+
+Readline Bare Essentials
+------------------------
+
+ In order to enter characters into the line, simply type them. The
+typed character appears where the cursor was, and then the cursor moves
+one space to the right. If you mistype a character, you can use DEL to
+back up, and delete the mistyped character.
+
+ Sometimes you may miss typing a character that you wanted to type,
+and not notice your error until you have typed several other
+characters. In that case, you can type C-b to move the cursor to the
+left, and then correct your mistake. Aftwerwards, you can move the
+cursor to the right with C-f.
+
+ When you add text in the middle of a line, you will notice that
+characters to the right of the cursor get `pushed over' to make room
+for the text that you have inserted. Likewise, when you delete text
+behind the cursor, characters to the right of the cursor get `pulled
+back' to fill in the blank space created by the removal of the text. A
+list of the basic bare essentials for editing the text of an input line
+follows.
+
+C-b
+ Move back one character.
+
+C-f
+ Move forward one character.
+
+DEL
+ Delete the character to the left of the cursor.
+
+C-d
+ Delete the character underneath the cursor.
+
+Printing characters
+ Insert itself into the line at the cursor.
+
+C-_
+ Undo the last thing that you did. You can undo all the way back
+ to an empty line.
+
+
+File: gdb.info, Node: Readline Movement Commands, Next: Readline Killing Commands, Prev: Readline Bare Essentials, Up: Readline Interaction
+
+Readline Movement Commands
+--------------------------
+
+ The above table describes the most basic possible keystrokes that
+you need in order to do editing of the input line. For your
+convenience, many other commands have been added in addition to C-b,
+C-f, C-d, and DEL. Here are some commands for moving more rapidly
+about the line.
+
+C-a
+ Move to the start of the line.
+
+C-e
+ Move to the end of the line.
+
+M-f
+ Move forward a word.
+
+M-b
+ Move backward a word.
+
+C-l
+ Clear the screen, reprinting the current line at the top.
+
+ Notice how C-f moves forward a character, while M-f moves forward a
+word. It is a loose convention that control keystrokes operate on
+characters while meta keystrokes operate on words.
+
+
+File: gdb.info, Node: Readline Killing Commands, Next: Readline Arguments, Prev: Readline Movement Commands, Up: Readline Interaction
+
+Readline Killing Commands
+-------------------------
+
+ "Killing" text means to delete the text from the line, but to save
+it away for later use, usually by "yanking" it back into the line. If
+the description for a command says that it `kills' text, then you can
+be sure that you can get the text back in a different (or the same)
+place later.
+
+ Here is the list of commands for killing text.
+
+C-k
+ Kill the text from the current cursor position to the end of the
+ line.
+
+M-d
+ Kill from the cursor to the end of the current word, or if between
+ words, to the end of the next word.
+
+M-DEL
+ Kill from the cursor to the start of the previous word, or if
+ between words, to the start of the previous word.
+
+C-w
+ Kill from the cursor to the previous whitespace. This is
+ different than M-DEL because the word boundaries differ.
+
+ And, here is how to "yank" the text back into the line. Yanking is
+
+C-y
+ Yank the most recently killed text back into the buffer at the
+ cursor.
+
+M-y
+ Rotate the kill-ring, and yank the new top. You can only do this
+ if the prior command is C-y or M-y.
+
+ When you use a kill command, the text is saved in a "kill-ring".
+Any number of consecutive kills save all of the killed text together, so
+that when you yank it back, you get it in one clean sweep. The kill
+ring is not line specific; the text that you killed on a previously
+typed line is available to be yanked back later, when you are typing
+another line.
+
+
+File: gdb.info, Node: Readline Arguments, Prev: Readline Killing Commands, Up: Readline Interaction
+
+Readline Arguments
+------------------
+
+ You can pass numeric arguments to Readline commands. Sometimes the
+argument acts as a repeat count, other times it is the sign of the
+argument that is significant. If you pass a negative argument to a
+command which normally acts in a forward direction, that command will
+act in a backward direction. For example, to kill text back to the
+start of the line, you might type M- C-k.
+
+ The general way to pass numeric arguments to a command is to type
+meta digits before the command. If the first `digit' you type is a
+minus sign (-), then the sign of the argument will be negative. Once
+you have typed one meta digit to get the argument started, you can type
+the remainder of the digits, and then the command. For example, to give
+the C-d command an argument of 10, you could type M-1 0 C-d.
+
+
+File: gdb.info, Node: Readline Init File, Prev: Readline Interaction, Up: Command Line Editing
+
+Readline Init File
+==================
+
+ Although the Readline library comes with a set of Emacs-like
+keybindings, it is possible that you would like to use a different set
+of keybindings. You can customize programs that use Readline by putting
+commands in an "init" file in your home directory. The name of this
+file is `~/.inputrc'.
+
+ When a program which uses the Readline library starts up, the
+`~/.inputrc' file is read, and the keybindings are set.
+
+ In addition, the C-x C-r command re-reads this init file, thus
+incorporating any changes that you might have made to it.
+
+* Menu:
+
+* Readline Init Syntax:: Syntax for the commands in `~/.inputrc'.
+* Readline Vi Mode:: Switching to `vi' mode in Readline.
+
+
+File: gdb.info, Node: Readline Init Syntax, Next: Readline Vi Mode, Up: Readline Init File
+
+Readline Init Syntax
+--------------------
+
+ There are only four constructs allowed in the `~/.inputrc' file:
+
+Variable Settings
+ You can change the state of a few variables in Readline. You do
+ this by using the `set' command within the init file. Here is how
+ you would specify that you wish to use Vi line editing commands:
+
+ set editing-mode vi
+
+ Right now, there are only a few variables which can be set; so few
+ in fact, that we just iterate them here:
+
+ `editing-mode'
+ The `editing-mode' variable controls which editing mode you
+ are using. By default, GNU Readline starts up in Emacs
+ editing mode, where the keystrokes are most similar to Emacs.
+ This variable can either be set to `emacs' or `vi'.
+
+ `horizontal-scroll-mode'
+ This variable can either be set to `On' or `Off'. Setting it
+ to `On' means that the text of the lines that you edit will
+ scroll horizontally on a single screen line when they are
+ larger than the width of the screen, instead of wrapping onto
+ a new screen line. By default, this variable is set to `Off'.
+
+ `mark-modified-lines'
+ This variable when set to `On', says to display an asterisk
+ (`*') at the starts of history lines which have been modified.
+ This variable is off by default.
+
+ `prefer-visible-bell'
+ If this variable is set to `On' it means to use a visible
+ bell if one is available, rather than simply ringing the
+ terminal bell. By default, the value is `Off'.
+
+Key Bindings
+ The syntax for controlling keybindings in the `~/.inputrc' file is
+ simple. First you have to know the name of the command that you
+ want to change. The following pages contain tables of the command
+ name, the default keybinding, and a short description of what the
+ command does.
+
+ Once you know the name of the command, simply place the name of
+ the key you wish to bind the command to, a colon, and then the
+ name of the command on a line in the `~/.inputrc' file. The name
+ of the key can be expressed in different ways, depending on which
+ is most comfortable for you.
+
+ KEYNAME: FUNCTION-NAME or MACRO
+ KEYNAME is the name of a key spelled out in English. For
+ example:
+ Control-u: universal-argument
+ Meta-Rubout: backward-kill-word
+ Control-o: ">&output"
+
+ In the above example, C-u is bound to the function
+ `universal-argument', and C-o is bound to run the macro
+ expressed on the right hand side (that is, to insert the text
+ `>&output' into the line).
+
+ "KEYSEQ": FUNCTION-NAME or MACRO
+ KEYSEQ differs from KEYNAME above in that strings denoting an
+ entire key sequence can be specified. Simply place the key
+ sequence in double quotes. GNU Emacs style key escapes can
+ be used, as in the following example:
+
+ "\C-u": universal-argument
+ "\C-x\C-r": re-read-init-file
+ "\e[11~": "Function Key 1"
+
+ In the above example, C-u is bound to the function
+ `universal-argument' (just as it was in the first example),
+ C-x C-r is bound to the function `re-read-init-file', and ESC
+ [ 1 1 ~ is bound to insert the text `Function Key 1'.
+
+* Menu:
+
+* Commands For Moving:: Moving about the line.
+* Commands For History:: Getting at previous lines.
+* Commands For Text:: Commands for changing text.
+* Commands For Killing:: Commands for killing and yanking.
+* Numeric Arguments:: Specifying numeric arguments, repeat counts.
+* Commands For Completion:: Getting Readline to do the typing for you.
+* Miscellaneous Commands:: Other miscillaneous commands.
+
+
+File: gdb.info, Node: Commands For Moving, Next: Commands For History, Up: Readline Init Syntax
+
+Commands For Moving
+-------------------
+
+`beginning-of-line (C-a)'
+ Move to the start of the current line.
+
+`end-of-line (C-e)'
+ Move to the end of the line.
+
+`forward-char (C-f)'
+ Move forward a character.
+
+`backward-char (C-b)'
+ Move back a character.
+
+`forward-word (M-f)'
+ Move forward to the end of the next word.
+
+`backward-word (M-b)'
+ Move back to the start of this, or the previous, word.
+
+`clear-screen (C-l)'
+ Clear the screen leaving the current line at the top of the screen.
+
+
+File: gdb.info, Node: Commands For History, Next: Commands For Text, Prev: Commands For Moving, Up: Readline Init Syntax
+
+Commands For Manipulating The History
+-------------------------------------
+
+`accept-line (Newline, Return)'
+ Accept the line regardless of where the cursor is. If this line is
+ non-empty, add it to the history list. If this line was a history
+ line, then restore the history line to its original state.
+
+`previous-history (C-p)'
+ Move `up' through the history list.
+
+`next-history (C-n)'
+ Move `down' through the history list.
+
+`beginning-of-history (M-<)'
+ Move to the first line in the history.
+
+`end-of-history (M->)'
+ Move to the end of the input history, i.e., the line you are
+ entering!
+
+`reverse-search-history (C-r)'
+ Search backward starting at the current line and moving `up'
+ through the history as necessary. This is an incremental search.
+
+`forward-search-history (C-s)'
+ Search forward starting at the current line and moving `down'
+ through the the history as neccessary.
+
+
+File: gdb.info, Node: Commands For Text, Next: Commands For Killing, Prev: Commands For History, Up: Readline Init Syntax
+
+Commands For Changing Text
+--------------------------
+
+`delete-char (C-d)'
+ Delete the character under the cursor. If the cursor is at the
+ beginning of the line, and there are no characters in the line, and
+ the last character typed was not C-d, then return EOF.
+
+`backward-delete-char (Rubout)'
+ Delete the character behind the cursor. A numeric arg says to kill
+ the characters instead of deleting them.
+
+`quoted-insert (C-q, C-v)'
+ Add the next character that you type to the line verbatim. This is
+ how to insert things like C-q for example.
+
+`tab-insert (M-TAB)'
+ Insert a tab character.
+
+`self-insert (a, b, A, 1, !, ...)'
+ Insert yourself.
+
+`transpose-chars (C-t)'
+ Drag the character before point forward over the character at
+ point. Point moves forward as well. If point is at the end of
+ the line, then transpose the two characters before point.
+ Negative args don't work.
+
+`transpose-words (M-t)'
+ Drag the word behind the cursor past the word in front of the
+ cursor moving the cursor over that word as well.
+
+`upcase-word (M-u)'
+ Uppercase all letters in the current (or following) word. With a
+ negative argument, do the previous word, but do not move point.
+
+`downcase-word (M-l)'
+ Lowercase all letters in the current (or following) word. With a
+ negative argument, do the previous word, but do not move point.
+
+`capitalize-word (M-c)'
+ Uppercase the first letter in the current (or following) word.
+ With a negative argument, do the previous word, but do not move
+ point.
+
+
+File: gdb.info, Node: Commands For Killing, Next: Numeric Arguments, Prev: Commands For Text, Up: Readline Init Syntax
+
+Killing And Yanking
+-------------------
+
+`kill-line (C-k)'
+ Kill the text from the current cursor position to the end of the
+ line.
+
+`backward-kill-line ()'
+ Kill backward to the beginning of the line. This is normally
+ unbound.
+
+`kill-word (M-d)'
+ Kill from the cursor to the end of the current word, or if between
+ words, to the end of the next word.
+
+`backward-kill-word (M-DEL)'
+ Kill the word behind the cursor.
+
+`unix-line-discard (C-u)'
+ Do what C-u used to do in Unix line input. We save the killed
+ text on the kill-ring, though.
+
+`unix-word-rubout (C-w)'
+ Do what C-w used to do in Unix line input. The killed text is
+ saved on the kill-ring. This is different than backward-kill-word
+ because the word boundaries differ.
+
+`yank (C-y)'
+ Yank the top of the kill ring into the buffer at point.
+
+`yank-pop (M-y)'
+ Rotate the kill-ring, and yank the new top. You can only do this
+ if the prior command is yank or yank-pop.
+
+
+File: gdb.info, Node: Numeric Arguments, Next: Commands For Completion, Prev: Commands For Killing, Up: Readline Init Syntax
+
+Specifying Numeric Arguments
+----------------------------
+
+`digit-argument (M-0, M-1, ... M--)'
+ Add this digit to the argument already accumulating, or start a new
+ argument. M- starts a negative argument.
+
+`universal-argument ()'
+ Do what C-u does in emacs. By default, this is not bound.
+
+
+File: gdb.info, Node: Commands For Completion, Next: Miscellaneous Commands, Prev: Numeric Arguments, Up: Readline Init Syntax
+
+Letting Readline Type For You
+-----------------------------
+
+`complete (TAB)'
+ Attempt to do completion on the text before point. This is
+ implementation defined. Generally, if you are typing a filename
+ argument, you can do filename completion; if you are typing a
+ command, you can do command completion, if you are typing in a
+ symbol to GDB, you can do symbol name completion, if you are
+ typing in a variable to Bash, you can do variable name
+ completion...
+
+`possible-completions (M-?)'
+ List the possible completions of the text before point.
+
+
+File: gdb.info, Node: Miscellaneous Commands, Prev: Commands For Completion, Up: Readline Init Syntax
+
+Some Miscellaneous Commands
+---------------------------
+
+`re-read-init-file (C-x C-r)'
+ Read in the contents of your `~/.inputrc' file, and incorporate
+ any bindings found there.
+
+`abort (C-g)'
+ Stop running the current editing command.
+
+`prefix-meta (ESC)'
+ Make the next character that you type be metafied. This is for
+ people without a meta key. Typing ESC f is equivalent to typing
+ M-f.
+
+`undo (C-_)'
+ Incremental undo, separately remembered for each line.
+
+`revert-line (M-r)'
+ Undo all changes made to this line. This is like typing the `undo'
+ command enough times to get back to the beginning.
+
+
+File: gdb.info, Node: Readline Vi Mode, Prev: Readline Init Syntax, Up: Readline Init File
+
+Readline Vi Mode
+----------------
+
+ While the Readline library does not have a full set of Vi editing
+functions, it does contain enough to allow simple editing of the line.
+
+ In order to switch interactively between Emacs and Vi editing modes,
+use the command M-C-j (toggle-editing-mode).
+
+ When you enter a line in Vi mode, you are already placed in
+`insertion' mode, as if you had typed an `i'. Pressing ESC switches
+you into `edit' mode, where you can edit the text of the line with the
+standard Vi movement keys, move to previous history lines with `k', and
+following lines with `j', and so forth.
+
+
+File: gdb.info, Node: Using History Interactively, Next: Renamed Commands, Prev: Command Line Editing, Up: Top
+
+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.
+
+
+File: gdb.info, Node: History Interaction, Up: Using History Interactively
+
+History Interaction
+===================
+
+ 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 "event", and the portions of that line that are
+acted upon are called "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.
+
+
+File: gdb.info, Node: Event Designators, Next: Word Designators, Up: History Interaction
+
+Event Designators
+-----------------
+
+ An event designator is a reference to a command line entry in the
+history list.
+
+`!'
+ Start a history subsititution, except when followed by a space,
+ tab, or the end of the line... = or (.
+
+`!!'
+ Refer to the previous command. This is a synonym for `!-1'.
+
+`!n'
+ Refer to command line N.
+
+`!-n'
+ Refer to the command line N lines back.
+
+`!string'
+ Refer to the most recent command starting with STRING.
+
+`!?string'[`?']
+ Refer to the most recent command containing STRING.
+
+
+File: gdb.info, Node: Word Designators, Next: Modifiers, Prev: Event Designators, Up: History Interaction
+
+Word Designators
+----------------
+
+ A : separates the event specification from the word designator. It
+can be omitted if the word designator begins with a ^, $, * or %.
+Words are numbered from the beginning of the line, with the first word
+being denoted by a 0 (zero).
+
+`0 (zero)'
+ The zero'th word. For many applications, this is the command word.
+
+`n'
+ The N'th word.
+
+`^'
+ The first argument. that is, word 1.
+
+`$'
+ The last argument.
+
+`%'
+ The word matched by the most recent `?string?' search.
+
+`x-y'
+ A range of words; `-Y' Abbreviates `0-Y'.
+
+`*'
+ All of the words, excepting the zero'th. This is a synonym for
+ `1-$'. It is not an error to use * if there is just one word in
+ the event. The empty string is returned in that case.
+
+
+File: gdb.info, Node: Modifiers, Prev: Word Designators, Up: History Interaction
+
+Modifiers
+---------
+
+ After the optional word designator, you can add a sequence of one or
+more of the following modifiers, each preceded by a :.
+
+`#'
+ 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.
+
+`h'
+ Remove a trailing pathname component, leaving only the head.
+
+`r'
+ Remove a trailing suffix of the form `.'SUFFIX, leaving the
+ basename.
+
+`e'
+ Remove all but the suffix.
+
+`t'
+ Remove all leading pathname components, leaving the tail.
+
+`p'
+ Print the new command but do not execute it.
+
+
+File: gdb.info, Node: Renamed Commands, Next: Formatting Documentation, Prev: Using History Interactively, Up: Top
+
+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:
+
+ OLD COMMAND NEW COMMAND
+ --------------- -------------------------------
+ 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]
+
+
+File: gdb.info, Node: Formatting Documentation, Next: Installing GDB, Prev: Renamed Commands, Up: Top
+
+Formatting Documentation
+************************
+
+ The GDB 4 release includes an already-formatted reference card, ready
+for printing with PostScript or GhostScript, in the `gdb' subdirectory
+of the main source directory(1). If you can use PostScript or
+GhostScript with your printer, you can print the reference card
+immediately with `refcard.ps'.
+
+ The release also includes the source for the reference card. You
+can format it, using TeX, by typing:
+
+ make refcard.dvi
+
+ 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 DVI output program.
+
+ 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 `texi2roff') to typeset the printed version.
+
+ GDB includes an already formatted copy of the on-line Info version of
+this manual in the `gdb' subdirectory. The main Info file is
+`gdb-VERSION-NUMBER/gdb/gdb.info', and it refers to subordinate files
+matching `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 `info' subsystem in GNU Emacs or the
+standalone `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 `texinfo-format-buffer' or `makeinfo'.
+
+ If you have `makeinfo' installed, and are in the top level GDB
+source directory (`gdb-4.11', in the case of version 4.11), you can
+make the Info file by typing:
+
+ cd gdb
+ make gdb.info
+
+ If you want to typeset and print copies of this manual, you need TeX,
+a program to print its DVI output files, and `texinfo.tex', the Texinfo
+definitions file.
+
+ TeX is a typesetting program; it does not print files directly, but
+produces output files called DVI files. To print a typeset document,
+you need a program to print DVI files. If your system has TeX
+installed, chances are it has such a program. The precise command to
+use depends on your system; `lpr -d' is common; another (for PostScript
+devices) is `dvips'. The DVI print command may require a file name
+without any extension or a `.dvi' extension.
+
+ TeX also requires a macro definitions file called `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.
+`texinfo.tex' is distributed with GDB and is located in the
+`gdb-VERSION-NUMBER/texinfo' directory.
+
+ If you have TeX and a DVI printer program installed, you can typeset
+and print this manual. First switch to the the `gdb' subdirectory of
+the main source directory (for example, to `gdb-4.11/gdb') and then
+type:
+
+ make gdb.dvi
+
+ ---------- Footnotes ----------
+
+ (1) In `gdb-4.11/gdb/refcard.ps' of the version 4.11 release.
+
+
+File: gdb.info, Node: Installing GDB, Next: Index, Prev: Formatting Documentation, Up: Top
+
+Installing GDB
+**************
+
+ GDB comes with a `configure' script that automates the process of
+preparing GDB for installation; you can then use `make' to build the
+`gdb' program.
+
+ 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 `gdb'.
+
+ For example, the GDB version 4.11 distribution is in the `gdb-4.11'
+directory. That directory contains:
+
+`gdb-4.11/configure (and supporting files)'
+ script for configuring GDB and all its supporting libraries.
+
+`gdb-4.11/gdb'
+ the source specific to GDB itself
+
+`gdb-4.11/bfd'
+ source for the Binary File Descriptor library
+
+`gdb-4.11/include'
+ GNU include files
+
+`gdb-4.11/libiberty'
+ source for the `-liberty' free software library
+
+`gdb-4.11/opcodes'
+ source for the library of opcode tables and disassemblers
+
+`gdb-4.11/readline'
+ source for the GNU command-line interface
+
+`gdb-4.11/glob'
+ source for the GNU filename pattern-matching subroutine
+
+`gdb-4.11/mmalloc'
+ source for the GNU memory-mapped malloc package
+
+ The simplest way to configure and build GDB is to run `configure'
+from the `gdb-VERSION-NUMBER' source directory, which in this example
+is the `gdb-4.11' directory.
+
+ First switch to the `gdb-VERSION-NUMBER' source directory if you are
+not already in it; then run `configure'. Pass the identifier for the
+platform on which GDB will run as an argument.
+
+ For example:
+
+ cd gdb-4.11
+ ./configure HOST
+ make
+
+where HOST is an identifier such as `sun4' or `decstation', that
+identifies the platform where GDB will run. (You can often leave off
+HOST; `configure' tries to guess the correct value by examining your
+system.)
+
+ Running `configure HOST' and then running `make' builds the `bfd',
+`readline', `mmalloc', and `libiberty' libraries, then `gdb' itself.
+The configured source files, and the binaries, are left in the
+corresponding source directories.
+
+ `configure' is a Bourne-shell (`/bin/sh') script; if your system
+does not recognize this automatically when you run a different shell,
+you may need to run `sh' on it explicitly:
+
+ sh configure HOST
+
+ If you run `configure' from a directory that contains source
+directories for multiple libraries or programs, such as the `gdb-4.11'
+source directory for version 4.11, `configure' creates configuration
+files for every directory level underneath (unless you tell it not to,
+with the `--norecursion' option).
+
+ You can run the `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 4.11, type the following to configure only
+the `bfd' subdirectory:
+
+ cd gdb-4.11/bfd
+ ../configure HOST
+
+ You can install `gdb' anywhere; it has no hardwired paths. However,
+you should make sure that the shell on your path (named by the `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
+
+
+File: gdb.info, Node: Separate Objdir, Next: Config Names, Up: Installing GDB
+
+Compiling GDB in another directory
+==================================
+
+ If you want to run GDB versions for several host or target machines,
+you need a different `gdb' compiled for each combination of host and
+target. `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 `make' program handles the `VPATH'
+feature (GNU `make' does), running `make' in each of these directories
+builds the `gdb' program specified there.
+
+ To build `gdb' in a separate directory, run `configure' with the
+`--srcdir' option to specify where to find the source. (You also need
+to specify a path to find `configure' itself from your working
+directory. If the path to `configure' would be the same as the
+argument to `--srcdir', you can leave out the `--srcdir' option; it
+will be assumed.)
+
+ For example, with version 4.11, you can build GDB in a separate
+directory for a Sun 4 like this:
+
+ cd gdb-4.11
+ mkdir ../gdb-sun4
+ cd ../gdb-sun4
+ ../gdb-4.11/configure sun4
+ make
+
+ When `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 `libiberty.a' in the
+directory `gdb-sun4/libiberty', and GDB itself in `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 `--target=TARGET' option to `configure'.
+
+ When you run `make' to build a program or library, you must run it
+in a configured directory--whatever directory you were in when you
+called `configure' (or one of its subdirectories).
+
+ The `Makefile' that `configure' generates in each source directory
+also runs recursively. If you type `make' in a source directory such
+as `gdb-4.11' (or in a separate configured directory configured with
+`--srcdir=PATH/gdb-4.11'), 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 `make' on them in parallel (for example, if
+they are NFS-mounted on each of the hosts); they will not interfere
+with each other.
+
+
+File: gdb.info, Node: Config Names, Next: configure Options, Prev: Separate Objdir, Up: Installing GDB
+
+Specifying names for hosts and targets
+======================================
+
+ The specifications used for hosts and targets in the `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:
+
+ ARCHITECTURE-VENDOR-OS
+
+ For example, you can use the alias `sun4' as a HOST argument, or as
+the value for TARGET in a `--target=TARGET' option. The equivalent
+full name is `sparc-sun-sunos4'.
+
+ The `configure' script accompanying GDB does not provide any query
+facility to list all supported host and target names or aliases.
+`configure' calls the Bourne shell script `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:
+
+ % 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
+
+`config.sub' is also distributed in the GDB source directory
+(`gdb-4.11', for version 4.11).
+
+
+File: gdb.info, Node: configure Options, Prev: Config Names, Up: Installing GDB
+
+`configure' options
+===================
+
+ Here is a summary of the `configure' options and arguments that are
+most often useful for building GDB. `configure' also has several other
+options not listed here. *note : (configure.info)What Configure Does,
+for a full explanation of `configure'.
+
+ configure [--help]
+ [--prefix=DIR]
+ [--srcdir=PATH]
+ [--norecursion] [--rm]
+ [--target=TARGET] HOST
+
+You may introduce options with a single `-' rather than `--' if you
+prefer; but you may abbreviate option names if you use `--'.
+
+`--help'
+ Display a quick summary of how to invoke `configure'.
+
+`-prefix=DIR'
+ Configure the source to install programs and files under directory
+ `DIR'.
+
+`--srcdir=PATH'
+ *Warning: using this option requires GNU `make', or another `make'
+ that implements the `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. `configure' writes configuration
+ specific files in the current directory, but arranges for them to
+ use the source in the directory PATH. `configure' will create
+ directories under the working directory in parallel to the source
+ directories below PATH.
+
+`--norecursion'
+ Configure only the directory level where `configure' is executed;
+ do not propagate configuration to subdirectories.
+
+`--rm'
+ *Remove* files otherwise built during configuration.
+
+`--target=TARGET'
+ Configure GDB for cross-debugging programs running on the specified
+ TARGET. Without this option, GDB is configured to debug programs
+ that run on the same machine (HOST) as GDB itself.
+
+ There is no convenient way to generate a list of all available
+ targets.
+
+`HOST ...'
+ Configure GDB to run on the specified HOST.
+
+ There is no convenient way to generate a list of all available
+ hosts.
+
+`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.
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.info-8 b/gnu/usr.bin/gdb/doc/gdb.info-8
new file mode 100644
index 0000000..1d259e0
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.info-8
@@ -0,0 +1,657 @@
+This is Info file ./gdb.info, produced by Makeinfo-1.52 from the input
+file gdb.texinfo.
+
+START-INFO-DIR-ENTRY
+* Gdb:: The GNU debugger.
+END-INFO-DIR-ENTRY
+ This file documents the GNU debugger GDB.
+
+ This is Edition 4.09, August 1993, of `Debugging with GDB: the GNU
+Source-Level Debugger' for GDB Version 4.11.
+
+ 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.
+
+ 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.
+
+
+File: gdb.info, Node: Index, Prev: Installing GDB, Up: Top
+
+Index
+*****
+
+* Menu:
+
+* #: Command Syntax.
+* $bpnum: Set Breaks.
+* $cdir: Source Path.
+* $cwd: Source Path.
+* $_: Convenience Vars.
+* $__: Convenience Vars.
+* .: M2 Scope.
+* .esgdbinit: Command Files.
+* .os68gdbinit: Command Files.
+* .vxgdbinit: Command Files.
+* /proc: Process Information.
+* 386: Remote Serial.
+* 680x0: Remote Serial.
+* @: Arrays.
+* # in Modula-2: GDB/M2.
+* $$: Value History.
+* $_ and info breakpoints: Set Breaks.
+* $_ and info line: Machine Code.
+* $_, $__, and value history: Memory.
+* $: Value History.
+* breakpoint subroutine, remote: Stub Contents.
+* heuristic-fence-post (MIPS): MIPS Stack.
+* remotedebug, MIPS protocol: MIPS Remote.
+* retransmit-timeout, MIPS protocol: MIPS Remote.
+* timeout, MIPS protocol: MIPS Remote.
+* vi style command editing: Readline Vi Mode.
+* .gdbinit: Command Files.
+* COFF versus C++: Cplus expressions.
+* ECOFF and C++: Cplus expressions.
+* ELF/DWARF and C++: Cplus expressions.
+* ELF/stabs and C++: Cplus expressions.
+* XCOFF and C++: Cplus expressions.
+* GDB bugs, reporting: Bug Reporting.
+* {TYPE}: Expressions.
+* a.out and C++: Cplus expressions.
+* abbreviation: Command Syntax.
+* active targets: Active Targets.
+* add-symbol-file: Files.
+* add-syms: Renamed Commands.
+* AMD 29K register stack: Registers.
+* AMD EB29K: Target Commands.
+* AMD29K via UDI: UDI29K Remote.
+* arguments (to your program): Arguments.
+* artificial array: Arrays.
+* assembly instructions: Machine Code.
+* assignment: Assignment.
+* attach: Attach.
+* attach: Attach.
+* automatic display: Auto Display.
+* b: Set Breaks.
+* backtrace: Backtrace.
+* break: Set Breaks.
+* break in overloaded functions: Debugging C plus plus.
+* breakpoint commands: Break Commands.
+* breakpoint conditions: Conditions.
+* breakpoint numbers: Breakpoints.
+* breakpoint on memory address: Breakpoints.
+* breakpoint on variable modification: Breakpoints.
+* breakpoints: Breakpoints.
+* bt: Backtrace.
+* bug criteria: Bug Criteria.
+* bug reports: Bug Reporting.
+* bugs in GDB: GDB Bugs.
+* c: Continuing and Stepping.
+* C and C++: C.
+* C and C++ checks: C Checks.
+* C and C++ constants: C Operators.
+* C and C++ defaults: C Defaults.
+* C and C++ operators: C.
+* C++: C.
+* C++ and object formats: Cplus expressions.
+* C++ exception handling: Debugging C plus plus.
+* C++ scope resolution: Variables.
+* C++ support, not in COFF: Cplus expressions.
+* C++ symbol decoding style: Print Settings.
+* C++ symbol display: Debugging C plus plus.
+* call: Calling.
+* call overloaded functions: Cplus expressions.
+* call stack: Stack.
+* calling functions: Calling.
+* calling make: Shell Commands.
+* casts, to view memory: Expressions.
+* catch: Exception Handling.
+* catch exceptions: Frame Info.
+* cd: Working Directory.
+* cdir: Source Path.
+* checks, range: Type Checking.
+* checks, type: Checks.
+* checksum, for GDB remote: Protocol.
+* clear: Delete Breaks.
+* clearing breakpoints, watchpoints: Delete Breaks.
+* colon, doubled as scope operator: M2 Scope.
+* colon-colon: M2 Scope.
+* colon-colon: Variables.
+* command files: Hooks.
+* command files: Command Files.
+* command line editing: Editing.
+* commands: Break Commands.
+* commands for C++: Debugging C plus plus.
+* commands to STDBUG (ST2000): ST2000 Remote.
+* comment: Command Syntax.
+* compilation directory: Source Path.
+* completion: Completion.
+* completion of quoted strings: Completion.
+* condition: Conditions.
+* conditional breakpoints: Conditions.
+* configuring GDB: Installing GDB.
+* confirmation: Messages/Warnings.
+* connect (to STDBUG): ST2000 Remote.
+* continue: Continuing and Stepping.
+* continuing: Continuing and Stepping.
+* controlling terminal: Input/Output.
+* convenience variables: Convenience Vars.
+* core: Files.
+* core dump file: Files.
+* core-file: Files.
+* CPU simulator: Simulator.
+* crash of debugger: Bug Criteria.
+* current directory: Source Path.
+* cwd: Source Path.
+* d: Delete Breaks.
+* debugger crash: Bug Criteria.
+* debugging optimized code: Compilation.
+* debugging stub, example: Protocol.
+* debugging target: Targets.
+* define: Define.
+* delete: Delete Breaks.
+* delete breakpoints: Delete Breaks.
+* delete display: Auto Display.
+* delete environment: Renamed Commands.
+* deleting breakpoints, watchpoints: Delete Breaks.
+* detach: Attach.
+* device: Hitachi Remote.
+* directories for source files: Source Path.
+* directory: Source Path.
+* directory, compilation: Source Path.
+* directory, current: Source Path.
+* dis: Disabling.
+* disable: Disabling.
+* disable breakpoints: Disabling.
+* disable display: Auto Display.
+* disabled breakpoints: Disabling.
+* disassemble: Machine Code.
+* display: Auto Display.
+* display of expressions: Auto Display.
+* do: Selection.
+* document: Define.
+* documentation: Formatting Documentation.
+* down: Selection.
+* down-silently: Selection.
+* download to H8/300 or H8/500: Files.
+* download to Hitachi SH: Files.
+* download to Nindy-960: Files.
+* download to VxWorks: VxWorks Download.
+* dynamic linking: Files.
+* eb.log: Remote Log.
+* EB29K board: EB29K Remote.
+* EBMON: Comms (EB29K).
+* echo: Output.
+* editing: Editing.
+* editing-mode: Readline Init Syntax.
+* emacs: Emacs.
+* enable: Disabling.
+* enable breakpoints: Disabling.
+* enable display: Auto Display.
+* enabled breakpoints: Disabling.
+* end: Break Commands.
+* entering numbers: Numbers.
+* environment (of your program): Environment.
+* error on valid input: Bug Criteria.
+* event designators: Event Designators.
+* examining data: Data.
+* examining memory: Memory.
+* exception handlers: Exception Handling.
+* exception handlers: Frame Info.
+* exceptionHandler: Bootstrapping.
+* exec-file: Files.
+* executable file: Files.
+* exiting GDB: Quitting GDB.
+* expansion: History Interaction.
+* expressions: Expressions.
+* expressions in C or C++: C.
+* expressions in C++: Cplus expressions.
+* expressions in Modula-2: Modula-2.
+* f: Selection.
+* fatal signal: Bug Criteria.
+* fatal signals: Signals.
+* fg: Continuing and Stepping.
+* file: Files.
+* finish: Continuing and Stepping.
+* flinching: Messages/Warnings.
+* floating point: Floating Point Hardware.
+* floating point registers: Registers.
+* floating point, MIPS remote: MIPS Remote.
+* flush_i_cache: Bootstrapping.
+* foo: Symbol Errors.
+* format options: Print Settings.
+* formatted output: Output Formats.
+* Fortran: Summary.
+* forward-search: Search.
+* frame: Selection.
+* frame: Frames.
+* frame number: Frames.
+* frame pointer: Frames.
+* frameless execution: Frames.
+* g++: C.
+* GDB reference card: Formatting Documentation.
+* gdbserver: Server.
+* getDebugChar: Bootstrapping.
+* GNU C++: C.
+* h: Help.
+* H8/300 or H8/500 download: Files.
+* H8/300 or H8/500 simulator: Simulator.
+* handle: Signals.
+* handle_exception: Stub Contents.
+* handling signals: Signals.
+* help: Help.
+* help target: Target Commands.
+* help user-defined: Define.
+* history expansion: History.
+* history file: History.
+* history number: Value History.
+* history save: History.
+* history size: History.
+* history substitution: History.
+* Hitachi SH download: Files.
+* Hitachi SH simulator: Simulator.
+* horizontal-scroll-mode: Readline Init Syntax.
+* i: Help.
+* i/o: Input/Output.
+* i386-stub.c: Remote Serial.
+* i960: i960-Nindy Remote.
+* ignore: Conditions.
+* ignore count (of breakpoint): Conditions.
+* INCLUDE_RDB: VxWorks Remote.
+* info: Help.
+* info address: Symbols.
+* info all-registers: Registers.
+* info args: Frame Info.
+* info breakpoints: Set Breaks.
+* info catch: Frame Info.
+* info convenience: Renamed Commands.
+* info copying: Renamed Commands.
+* info directories: Renamed Commands.
+* info display: Auto Display.
+* info editing: Renamed Commands.
+* info f: Frame Info.
+* info files: Files.
+* info float: Floating Point Hardware.
+* info frame: Frame Info.
+* info frame: Show.
+* info functions: Symbols.
+* info history: Renamed Commands.
+* info line: Machine Code.
+* info locals: Frame Info.
+* info proc: Process Information.
+* info proc id: Process Information.
+* info proc mappings: Process Information.
+* info proc status: Process Information.
+* info proc times: Process Information.
+* info program: Stopping.
+* info registers: Registers.
+* info s: Backtrace.
+* info set: Help.
+* info share: Files.
+* info sharedlibrary: Files.
+* info signals: Signals.
+* info source: Symbols.
+* info source: Show.
+* info sources: Symbols.
+* info stack: Backtrace.
+* info target: Files.
+* info targets: Renamed Commands.
+* info terminal: Input/Output.
+* info types: Symbols.
+* info values: Renamed Commands.
+* info variables: Symbols.
+* info version: Renamed Commands.
+* info warranty: Renamed Commands.
+* info watchpoints: Set Watchpoints.
+* inheritance: Debugging C plus plus.
+* init file: Command Files.
+* init file name: Command Files.
+* initial frame: Frames.
+* innermost frame: Frames.
+* inspect: Data.
+* installation: Installing GDB.
+* instructions, assembly: Machine Code.
+* Intel: Remote Serial.
+* interaction, readline: Readline Interaction.
+* internal GDB breakpoints: Set Breaks.
+* interrupt: Quitting GDB.
+* interrupting remote programs: Debug Session.
+* invalid input: Bug Criteria.
+* jump: Jumping.
+* kill: Kill Process.
+* l: List.
+* languages: Languages.
+* latest breakpoint: Set Breaks.
+* leaving GDB: Quitting GDB.
+* linespec: List.
+* list: List.
+* listing machine instructions: Machine Code.
+* load: Files.
+* log file for EB29K: Remote Log.
+* m68k-stub.c: Remote Serial.
+* machine instructions: Machine Code.
+* maint info breakpoints: Set Breaks.
+* maint print psymbols: Symbols.
+* maint print symbols: Symbols.
+* make: Shell Commands.
+* mapped: Files.
+* mark-modified-lines: Readline Init Syntax.
+* member functions: Cplus expressions.
+* memory tracing: Breakpoints.
+* memory, viewing as typed object: Expressions.
+* memory-mapped symbol file: Files.
+* memset: Bootstrapping.
+* MIPS boards: MIPS Remote.
+* MIPS remote floating point: MIPS Remote.
+* MIPS stack: MIPS Stack.
+* Modula-2: Modula-2.
+* Modula-2 built-ins: M2 Operators.
+* Modula-2 checks: M2 Checks.
+* Modula-2 constants: Built-In Func/Proc.
+* Modula-2 defaults: M2 Defaults.
+* Modula-2 operators: M2 Operators.
+* Modula-2, deviations from: Deviations.
+* Motorola 680x0: Remote Serial.
+* multiple targets: Active Targets.
+* n: Continuing and Stepping.
+* names of symbols: Symbols.
+* namespace in C++: Cplus expressions.
+* negative breakpoint numbers: Set Breaks.
+* next: Continuing and Stepping.
+* nexti: Continuing and Stepping.
+* ni: Continuing and Stepping.
+* Nindy: i960-Nindy Remote.
+* number representation: Numbers.
+* numbers for breakpoints: Breakpoints.
+* object formats and C++: Cplus expressions.
+* online documentation: Help.
+* optimized code, debugging: Compilation.
+* outermost frame: Frames.
+* output: Output.
+* output formats: Output Formats.
+* overloading: Breakpoint Menus.
+* overloading in C++: Debugging C plus plus.
+* packets, reporting on stdout: Protocol.
+* partial symbol dump: Symbols.
+* patching binaries: Patching.
+* path: Environment.
+* pauses in output: Screen Size.
+* pipes: Starting.
+* prefer-visible-bell: Readline Init Syntax.
+* print: Data.
+* print settings: Print Settings.
+* printf: Output.
+* printing data: Data.
+* process image: Process Information.
+* prompt: Prompt.
+* protocol, GDB remote serial: Protocol.
+* ptype: Symbols.
+* putDebugChar: Bootstrapping.
+* pwd: Working Directory.
+* q: Quitting GDB.
+* quit: Quitting GDB.
+* quotes in commands: Completion.
+* quoting names: Symbols.
+* raise exceptions: Exception Handling.
+* range checking: Type Checking.
+* rbreak: Set Breaks.
+* reading symbols immediately: Files.
+* readline: Editing.
+* readnow: Files.
+* redirection: Input/Output.
+* reference card: Formatting Documentation.
+* reference declarations: Cplus expressions.
+* register stack, AMD29K: Registers.
+* registers: Registers.
+* regular expression: Set Breaks.
+* reloading symbols: Messages/Warnings.
+* remote connection without stubs: Server.
+* remote debugging: Remote.
+* remote programs, interrupting: Debug Session.
+* remote serial debugging summary: Debug Session.
+* remote serial debugging, overview: Remote Serial.
+* remote serial protocol: Protocol.
+* remote serial stub: Stub Contents.
+* remote serial stub list: Remote Serial.
+* remote serial stub, initialization: Stub Contents.
+* remote serial stub, main routine: Stub Contents.
+* remote stub, example: Protocol.
+* remote stub, support routines: Bootstrapping.
+* repeating commands: Command Syntax.
+* reporting bugs in GDB: GDB Bugs.
+* reset: Nindy Reset.
+* response time, MIPS debugging: MIPS Stack.
+* resuming execution: Continuing and Stepping.
+* RET: Command Syntax.
+* return: Returning.
+* returning from a function: Returning.
+* reverse-search: Search.
+* run: Starting.
+* running: Starting.
+* running 29K programs: EB29K Remote.
+* running VxWorks tasks: VxWorks Attach.
+* s: Continuing and Stepping.
+* saving symbol table: Files.
+* scope: M2 Scope.
+* search: Search.
+* searching: Search.
+* selected frame: Stack.
+* serial connections, debugging: Protocol.
+* serial device, Hitachi micros: Hitachi Remote.
+* serial line speed, Hitachi micros: Hitachi Remote.
+* serial line, target remote: Debug Session.
+* serial protocol, GDB remote: Protocol.
+* set addressprint: Renamed Commands.
+* set args: Arguments.
+* set array-max: Renamed Commands.
+* set arrayprint: Renamed Commands.
+* set asm-demangle: Renamed Commands.
+* set caution: Renamed Commands.
+* set check: Range Checking.
+* set check: Type Checking.
+* set check range: Range Checking.
+* set check type: Type Checking.
+* set complaints: Messages/Warnings.
+* set confirm: Messages/Warnings.
+* set demangle: Renamed Commands.
+* set demangle-style: Print Settings.
+* set editing: Editing.
+* set environment: Environment.
+* set height: Screen Size.
+* set history expansion: History.
+* set history filename: History.
+* set history save: History.
+* set history size: History.
+* set history write: Renamed Commands.
+* set language: Manually.
+* set listsize: List.
+* set mipsfpu off: MIPS Remote.
+* set prettyprint: Renamed Commands.
+* set print address: Print Settings.
+* set print array: Print Settings.
+* set print asm-demangle: Print Settings.
+* set print demangle: Print Settings.
+* set print elements: Print Settings.
+* set print max-symbolic-offset: Print Settings.
+* set print object: Print Settings.
+* set print pretty: Print Settings.
+* set print sevenbit-strings: Print Settings.
+* set print symbol-filename: Print Settings.
+* set print union: Print Settings.
+* set print vtbl: Print Settings.
+* set prompt: Prompt.
+* set radix: Numbers.
+* set remotedebug: Protocol.
+* set retransmit-timeout: MIPS Remote.
+* set rstack_high_address: Registers.
+* set screen-height: Renamed Commands.
+* set screen-width: Renamed Commands.
+* set sevenbit-strings: Renamed Commands.
+* set symbol-reloading: Messages/Warnings.
+* set timeout: MIPS Remote.
+* set unionprint: Renamed Commands.
+* set variable: Assignment.
+* set verbose: Messages/Warnings.
+* set vtblprint: Renamed Commands.
+* set width: Screen Size.
+* set write: Patching.
+* setting variables: Assignment.
+* setting watchpoints: Set Watchpoints.
+* set_debug_traps: Stub Contents.
+* share: Files.
+* shared libraries: Files.
+* sharedlibrary: Files.
+* shell: Shell Commands.
+* shell escape: Shell Commands.
+* show: Help.
+* show addressprint: Renamed Commands.
+* show args: Arguments.
+* show array-max: Renamed Commands.
+* show arrayprint: Renamed Commands.
+* show asm-demangle: Renamed Commands.
+* show caution: Renamed Commands.
+* show check range: Range Checking.
+* show check type: Type Checking.
+* show commands: History.
+* show complaints: Messages/Warnings.
+* show confirm: Messages/Warnings.
+* show convenience: Convenience Vars.
+* show copying: Help.
+* show demangle: Renamed Commands.
+* show demangle-style: Print Settings.
+* show directories: Source Path.
+* show editing: Editing.
+* show environment: Environment.
+* show height: Screen Size.
+* show history: History.
+* show history write: Renamed Commands.
+* show language: Show.
+* show listsize: List.
+* show paths: Environment.
+* show prettyprint: Renamed Commands.
+* show print address: Print Settings.
+* show print array: Print Settings.
+* show print asm-demangle: Print Settings.
+* show print demangle: Print Settings.
+* show print elements: Print Settings.
+* show print max-symbolic-offset: Print Settings.
+* show print object: Print Settings.
+* show print pretty: Print Settings.
+* show print sevenbit-strings: Print Settings.
+* show print symbol-filename: Print Settings.
+* show print union: Print Settings.
+* show print vtbl: Print Settings.
+* show prompt: Prompt.
+* show radix: Numbers.
+* show remotedebug: Protocol.
+* show retransmit-timeout: MIPS Remote.
+* show rstack_high_address: Registers.
+* show screen-height: Renamed Commands.
+* show screen-width: Renamed Commands.
+* show sevenbit-strings: Renamed Commands.
+* show timeout: MIPS Remote.
+* show unionprint: Renamed Commands.
+* show user: Define.
+* show values: Value History.
+* show verbose: Messages/Warnings.
+* show version: Help.
+* show vtblprint: Renamed Commands.
+* show warranty: Help.
+* show width: Screen Size.
+* show write: Patching.
+* si: Continuing and Stepping.
+* signal: Signaling.
+* signals: Signals.
+* silent: Break Commands.
+* sim: Simulator.
+* simulator: Simulator.
+* simulator, H8/300 or H8/500: Simulator.
+* simulator, Hitachi SH: Simulator.
+* simulator, Z8000: Simulator.
+* size of screen: Screen Size.
+* source: Command Files.
+* source path: Source Path.
+* sparc-stub.c: Remote Serial.
+* speed: Hitachi Remote.
+* st2000 CMD: ST2000 Remote.
+* ST2000 auxiliary commands: ST2000 Remote.
+* stack frame: Frames.
+* stack on MIPS: MIPS Stack.
+* stacking targets: Active Targets.
+* starting: Starting.
+* STDBUG commands (ST2000): ST2000 Remote.
+* step: Continuing and Stepping.
+* stepi: Continuing and Stepping.
+* stepping: Continuing and Stepping.
+* stub example, remote debugging: Protocol.
+* stupid questions: Messages/Warnings.
+* symbol decoding style, C++: Print Settings.
+* symbol dump: Symbols.
+* symbol names: Symbols.
+* symbol overloading: Breakpoint Menus.
+* symbol table: Files.
+* symbol-file: Files.
+* symbols, reading immediately: Files.
+* target: Targets.
+* target amd-eb: Target Commands.
+* target core: Target Commands.
+* target exec: Target Commands.
+* target hms: Target Commands.
+* target mips PORT: MIPS Remote.
+* target nindy: Target Commands.
+* target remote: Target Commands.
+* target sim: Target Commands.
+* target sim: Simulator.
+* target st2000: Target Commands.
+* target udi: Target Commands.
+* target vxworks: Target Commands.
+* tbreak: Set Breaks.
+* TCP port, target remote: Debug Session.
+* terminal: Input/Output.
+* this: Cplus expressions.
+* toggle-editing-mode: Readline Vi Mode.
+* tty: Input/Output.
+* type casting memory: Expressions.
+* type checking: Checks.
+* type conversions in C++: Cplus expressions.
+* u: Continuing and Stepping.
+* udi: UDI29K Remote.
+* UDI: UDI29K Remote.
+* undisplay: Auto Display.
+* unset: Renamed Commands.
+* unset environment: Environment.
+* until: Continuing and Stepping.
+* up: Selection.
+* up-silently: Selection.
+* user-defined command: Define.
+* value history: Value History.
+* variable name conflict: Variables.
+* variable values, wrong: Variables.
+* variables, setting: Assignment.
+* version number: Help.
+* VxWorks: VxWorks Remote.
+* watch: Set Watchpoints.
+* watchpoints: Breakpoints.
+* whatis: Symbols.
+* where: Backtrace.
+* word completion: Completion.
+* working directory: Source Path.
+* working directory (of your program): Working Directory.
+* working language: Languages.
+* writing into corefiles: Patching.
+* writing into executables: Patching.
+* wrong values: Variables.
+* x: Memory.
+* Z8000 simulator: Simulator.
+
+
diff --git a/gnu/usr.bin/gdb/doc/gdb.texinfo b/gnu/usr.bin/gdb/doc/gdb.texinfo
new file mode 100644
index 0000000..a2f293d
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdb.texinfo
@@ -0,0 +1,8591 @@
+\input texinfo @c -*-texinfo-*-
+@c Copyright (c) 1988 1989 1990 1991 1992 1993 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 ===> NOTE! <==
+@c Determine the edition number in *three* places by hand:
+@c 1. First ifinfo section 2. title page 3. top node
+@c To find the locations, search for !!set
+
+@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:: The GNU debugger.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+@c
+@c
+@ifinfo
+This file documents the GNU debugger @value{GDBN}.
+
+@c !!set edition, date, version
+This is Edition 4.09, August 1993,
+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
+@c !!set edition, date, version
+@subtitle Edition 4.09, for @value{GDBN} version @value{GDBVN}
+@subtitle August 1993
+@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.
+
+@c !!set edition, date, version
+This is Edition 4.09, August 1993, 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
+@ifclear MOD2
+You can use @value{GDBN} to debug programs written in C or C++.
+@end ifclear
+@ifset MOD2
+You can use @value{GDBN} to debug programs written in C, C++, and
+Modula-2.
+@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, etc.
+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.11, 4.10, 4.9), Stu Grossman and John Gilmore (releases
+4.8, 4.7, 4.6, 4.5, 4.4), John Gilmore (releases 4.3, 4.2, 4.1, 4.0, and
+3.9); Jim Kingdon (releases 3.5, 3.4, 3.3); and Randy Smith (releases
+3.2, 3.1, 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.
+Keith Packard contributed NS32K support. Doug Rabson contributed
+Acorn Risc Machine 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.
+
+@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, realtime systems over a TCP/IP connection, etc. 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 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
+will 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 will 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:: @value{GDBN} and the UDI protocol for AMD29K
+* EB29K Remote:: @value{GDBN} with a remote EB29K
+@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 will be @file{./fred.syms}.
+Future @value{GDBN} debugging sessions will notice the presence of this file,
+and will 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}) will not exit from @value{GDBN}, but rather
+will terminate the action of any @value{GDBN} command that is in progress and
+return 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 for which 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} will fill in the
+word, and wait 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} will sound a bell. You can either supply more
+characters and try again, or just press @key{TAB} a second time, and
+@value{GDBN} will display 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 will display 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 will require
+quotes. When this happens, @value{GDBN} will insert 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} will display 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
+@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 will show 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} will never see 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 will 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 will be given to
+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} will discard its symbol table and
+re-read it. 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} 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} will execute 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 will be 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 will 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} will show 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} will 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} will 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, you will be asked 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} will notice that the file has changed, and
+will re-read the symbol table (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
+@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
+@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 various
+conditions to control in finer detail whether your program will stop.
+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 will stop 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 will cause your program to 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} will stop
+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 disabled 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. They can
+be deleted, disabled, made conditional, etc., in the standard ways.
+
+@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. Some
+processors provide special hardware to support watchpoint evaluation; future
+releases of @value{GDBN} will use such hardware if it is available.
+
+@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 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}.
+These will be corrected in a future release.
+
+@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 interactively install an exception handler.
+@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 will stop 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 will stop your program, but
+when it does so it will become disabled. A breakpoint set
+with the @code{tbreak} command starts out in this state.
+@item
+Enabled for deletion. The breakpoint will stop your program, but
+immediately after it does so it will be 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. Each will be disabled
+again the next time it stops your program.
+
+@item enable @r{[}breakpoints@r{]} delete @var{bnums}@dots{}
+Enable the specified breakpoints to work once and then die. Each of
+the breakpoints will be deleted the next time it stops your program.
+@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 will 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}. From now on, this breakpoint will stop
+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 will not stop the next @var{n} times it
+is reached.
+
+@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 will 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, the condition will
+be checked.
+
+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
+will 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 will be 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
+@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.
+@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} will cause your program to continue execution
+until the loop is exited. In contrast, a @code{next} command at the end
+of a loop will simply step back to the beginning of the loop, which
+would force 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 will cause the next instruction to be executed to
+be displayed automatically at each stop. @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 will be
+able to handle the signal, or may be terminated 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 will see 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 that
+signal will be seen by your program when you later continue it.
+
+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
+
+@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} will generate 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} will nevertheless regard 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.
+
+@ifset SPARC
+On the SPARC architecture, @code{frame} needs two addresses to
+select an arbitrary frame: a frame pointer and a stack pointer.
+@c note to future updaters: this is conditioned on a flag
+@c FRAME_SPECIFICATION_DYADIC in the tm-*.h files, currently only used
+@c by SPARC, hence the specific attribution. Generalize or list all
+@c possibilities if more supported machines start doing this.
+@end ifset
+
+@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.
+
+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 will
+print 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.
+
+@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 @var{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} will currently display by
+default.
+@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} will, as a last resort, look in the current
+directory.
+
+Whenever you reset or rearrange the source path, @value{GDBN} will clear out
+any information it has cached about where source files are found, where
+each line is in the file, etc.
+
+@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 it will be searched 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; the function surrounding this value
+will be dumped. 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
+Print as an address, both absolute in hex and as an offset from the
+nearest preceding symbol. This format can be 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 will work. The output
+specifications @samp{4xw} and @samp{4wx} mean exactly the same thing.
+(However, the count @var{n} must come first; @samp{wx4} will 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} will print 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} will 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} will 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}, then this argument will be displayed while your program
+continues to stop inside that function. When it stops elsewhere---where
+there is no variable @code{last_char}---display is disabled. 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} will print 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 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 @code{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
+
+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} will print in a
+symbolic address.
+@end table
+
+@table @code
+@item set print array
+@itemx set print array on
+@kindex set print array
+@value{GDBN} will 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 will stop 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} will print
+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} will use 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} will display any eight-bit characters (in strings or character
+values) using the notation @code{\}@var{nnn}. For example, @kbd{M-a} is
+displayed as @code{\341}.
+
+@item set print sevenbit-strings off
+Print using either seven-bit or eight-bit characters, as required. This
+is the default.
+
+@item show print sevenbit-strings
+@kindex show print sevenbit-strings
+Show whether or not @value{GDBN} will print 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 will be 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 will be 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 will be 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 will make 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 will 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 will 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 is the
+language that will become the working language if you ever use an
+identifier that is in 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} will 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 will accept, 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++}.
+@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++
+@quotation
+@emph{Warning:} Most of these extensions depend on the use of additional
+debugging information in the symbol table, and thus require a rich,
+extendable object code format. In particular, if your system uses
+a.out, MIPS @sc{ecoff}, RS/6000 @sc{xcoff}, or Sun @sc{elf} with stabs
+extensions to the symbol table, these facilities are all available.
+Where the object code format is standard @sc{coff}, on the other hand,
+most of the C++ support in @value{GDBN} will @emph{not} work, nor can it.
+For the standard SVr4 debugging format, @sc{dwarf} in @sc{elf}, the
+standard is still evolving, so the C++ support in @value{GDBN} is still
+fragile; when this debugging format stabilizes, however, C++ support
+will also be available on systems that use it.
+@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} will resolve 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} will 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} will
+consider 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
+will also be printed.
+Otherwise, it will appear 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 will most likely
+result in 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}
+will treat 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} will treat 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} will set 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} will print 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} will search 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 will stop
+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 it is continued. For example,
+
+@example
+set $pc = 0x485
+@end example
+
+@noindent
+causes the next @code{continue} command or stepping command to 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} will open executable
+@ifclear BARETARGET
+and core
+@end ifclear
+files for both reading and writing; if you specify @samp{set write
+off} (the default), @value{GDBN} will open 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
+will be 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 symbol table file
+@file{@var{filename}.syms} may be available for @var{filename}. If it
+is, @value{GDBN} will map 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} will search 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} will not repeat if you press @key{RET} again after
+executing it once.
+
+When @value{GDBN} is configured for a particular environment, it will
+understand 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 will 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} will always attempt 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, like a.out, the object file format fixes
+the address and so it won't necessarily match the address you gave to
+the linker.
+
+@ifset VXWORKS
+On VxWorks, @code{load} will dynamically link @var{filename} 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} will
+download @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} will 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} will 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 targets} 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 path
+name and remembers it that way.
+
+@ifclear BARETARGET
+@cindex shared libraries
+@value{GDBN} supports SunOS, SVR4, 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} will not understand
+references to a function in a shared library, however---unless you are
+debugging a core file).
+@c FIXME: next @value{GDBN} release should permit some refs to undef
+@c FIXME...symbols---eg in a break cmd---assuming they are from a shared lib
+
+@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 will only load 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} will occasionally encounter 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 will have 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
+will usually allow your program to be debugged, though certain symbols
+will not be 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 will use 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 will 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,,@value{GDBN} and 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, ,@value{GDBN} with a remote EB29K}.
+
+@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 will run on the remote system to
+communicate with GDB.
+
+Other remote targets may be available in your
+configuration of GDB; use @code{help targets} 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:: @value{GDBN} and the UDI protocol for AMD29K
+* EB29K Remote:: @value{GDBN} with a remote EB29K
+@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
+@item set history filename @var{fname}
+Set the name of the @value{GDBN} command history file to @var{fname}. This is
+the file from which @value{GDBN} will read an initial command history
+list or to which it will write this list when it exits. This list is
+accessed 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} will keep 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 will 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} will 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
+will set the base to decimal. On the other hand, @samp{set radix 10}
+will leave 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 will make @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} will print
+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
+will 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 and then the init file
+(if any) in the current working directory. (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 will be 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 will have no reason to use them.
+
+@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 will 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 will proceed 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 a full path 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) will make 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 &} will both indicate that you
+wish special formatting, and act 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 will recreate
+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 will 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, etc.
+
+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 will be 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{path}/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{path}@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}}.
+
+@item --srcdir=@var{path}
+@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{path}. @code{configure} will create directories under
+the working directory in parallel to the source directories below
+@var{path}.
+
+@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..a2f6257
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/gdbint.texinfo
@@ -0,0 +1,2658 @@
+\input texinfo
+@setfilename gdbint.info
+@c $Id: gdbint.texinfo,v 1.1.1.1 1993/10/30 21:59:41 jkh 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 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.1.1.1 $} % 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 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
+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 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 BADMAG
+coffread.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 BREAKPOINT
+tm-m68k.h
+@item BREAKPOINT_DEBUG
+breakpoint.c
+@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 BSTRING
+regex.c
+@item CALL_DUMMY
+valops.c
+@item CALL_DUMMY_LOCATION
+inferior.h
+@item CALL_DUMMY_STACK_ADJUST
+valops.c
+@item CANNOT_FETCH_REGISTER
+hppabsd-xdep.c
+@item CANNOT_STORE_REGISTER
+findvar.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 CREATE_INFERIOR_HOOK
+infrun.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
+remote-adapt.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 FRAMELESS_FUNCTION_INVOCATION
+blockframe.c
+@item FRAME_ARGS_ADDRESS_CORRECT
+stack.c
+@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
+tm-m68k.h
+@item FRAME_SPECIFICATION_DYADIC
+stack.c
+@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
+ieee-float.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_DEBUG
+ieee-float.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, it 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_PROLOGUE
+tm-m68k.h
+@item SKIP_PROLOGUE_FRAMELESS_P
+blockframe.c
+@item SKIP_TRAMPOLINE_CODE
+infrun.c
+@item SOLIB_ADD
+core.c
+@item SOLIB_CREATE_INFERIOR_HOOK
+infrun.c
+@item STACK_ALIGN
+valops.c
+@item START_INFERIOR_TRAPS_EXPECTED
+infrun.c
+@item STOP_SIGNAL
+main.c
+@item STORE_RETURN_VALUE
+tm-m68k.h
+@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 TDESC
+infrun.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 _LANG_c
+language.c
+@item _LANG_m2
+language.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 BADMAG
+coffread.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 BREAKPOINT
+tm-m68k.h
+@item BREAKPOINT_DEBUG
+breakpoint.c
+@item BSTRING
+regex.c
+@item CALL_DUMMY
+valops.c
+@item CALL_DUMMY_LOCATION
+inferior.h
+@item CALL_DUMMY_STACK_ADJUST
+valops.c
+@item CANNOT_FETCH_REGISTER
+hppabsd-xdep.c
+@item CANNOT_STORE_REGISTER
+findvar.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 CREATE_INFERIOR_HOOK
+infrun.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
+remote-adapt.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 FPU
+Unused? 6-oct-92 rich@@cygnus.com. FIXME.
+@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
+tm-m68k.h
+@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 HOST_BYTE_ORDER
+ieee-float.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 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_DEBUG
+ieee-float.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 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 NFAILURES
+regex.c
+@item NNPC_REGNUM
+infrun.c
+@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_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 RE_NREGS
+regex.h
+@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 SIGN_EXTEND_CHAR
+regex.c
+@item SIGTRAP_STOP_AFTER_LOAD
+infrun.c
+@item SKIP_PROLOGUE
+tm-m68k.h
+@item SKIP_PROLOGUE_FRAMELESS_P
+blockframe.c
+@item SKIP_TRAMPOLINE_CODE
+infrun.c
+@item SOLIB_ADD
+core.c
+@item SOLIB_CREATE_INFERIOR_HOOK
+infrun.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
+tm-m68k.h
+@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 TARGET_BYTE_ORDER
+defs.h
+@item TARGET_CHAR_BIT
+defs.h
+@item TARGET_COMPLEX_BIT
+defs.h
+@item TARGET_DOUBLE_BIT
+defs.h
+@item TARGET_DOUBLE_COMPLEX_BIT
+defs.h
+@item TARGET_FLOAT_BIT
+defs.h
+@item TARGET_INT_BIT
+defs.h
+@item TARGET_LONG_BIT
+defs.h
+@item TARGET_LONG_DOUBLE_BIT
+defs.h
+@item TARGET_LONG_LONG_BIT
+defs.h
+@item TARGET_PTR_BIT
+defs.h
+@item TARGET_READ_PC
+@item TARGET_WRITE_PC
+@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 TARGET_SHORT_BIT
+defs.h
+@item TDESC
+infrun.c
+@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 _LANG_c
+language.c
+@item _LANG_m2
+language.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 sparc
+regex.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 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/libgdb.texinfo b/gnu/usr.bin/gdb/doc/libgdb.texinfo
new file mode 100644
index 0000000..c67c3a8
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/libgdb.texinfo
@@ -0,0 +1,1471 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename libgdb.info
+@settitle Libgdb
+@setchapternewpage odd
+@c %**end of header
+
+@ifinfo
+This file documents libgdb, the GNU library for symbolic debuggers.
+
+Copyright 1993 Cygnus Support
+
+Permission is granted to ...
+@end ifinfo
+
+@c This title page illustrates only one of the
+@c two methods of forming a title page.
+
+@titlepage
+@title Libgdb
+@subtitle Version 0.1
+@subtitle 27 Sep 1993
+@author Thomas Lord
+
+@c The following two commands
+@c start the copyright page.
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1993 COPYRIGHT-OWNER
+
+Published by ...
+
+Permission is granted to ...
+@end titlepage
+
+@node Top, Overview, (dir), (dir)
+
+@ifinfo
+
+Libgdb is a library which provides the core functionality of a symbolic
+debugger. It is derived from GNU GDB and depends on the BFD library.
+
+This is an early draft of this document. Subsequent versions will likely
+contain revisions, deletions and additions.
+
+This document applies to version 0.0.
+
+Text marked `[[[' indicates areas which require expansion.
+
+Many nodes describe library entry points by giving a prototype and brief
+description:
+
+@deftypefun {const char **} gdb_warranty ()
+(warranty_info)
+Return a pointer to the text of the GDB disclaimer.
+@end deftypefun
+
+The parenthesized symbols (e.g. `(warranty_info)') refer to the
+existing GDB source and generally indicate where to find code with
+which to implement the library function.
+@end ifinfo
+
+@menu
+* Copying:: Your rights and freedoms.
+* Overview:: The basics of libgdb and this document.
+* Conventions:: Programming conventions for users of libgdb.
+* Targets:: Selecting debugging targets and symbol tables.
+* Symtabs:: Accessing symbol tables and debugging information.
+* Source:: Relating inferiors to source files.
+* Running:: Creating, continuing, and stepping through an
+ inferior process.
+* Stopping:: Using breakpoints, signaling an inferior.
+* Stack:: Accessing an inferior's execution stack.
+* Expressions:: How to parse and evaluate expressions in the
+ context of an inferior.
+* Values:: Data from the inferior, the values of expressions.
+* Examining:: Formatting values as strings.
+* Types:: Examining the types of an inferiors data.
+@end menu
+
+
+@node Copying, Overview, top, top
+@comment node-name, next, previous, up
+@chapter Copying
+@cindex copying
+
+blah blah
+
+@node Overview, Conventions, Copying, top
+@comment node-name, next, previous, up
+@chapter Overview
+@cindex overview
+@cindex definitions
+
+
+Libgdb is a library which provides the core functionality of a symbolic
+debugger. It is derived from GNU GDB and depends on the BFD library.
+
+target
+inferior
+
+
+
+@node Conventions, Targets, Overview, top
+@comment node-name, next, previous, up
+@chapter Programming Conventions for Libgdb Clients
+@cindex Conventions
+
+@heading Naming Conventions
+
+Names intentionally exported from libgdb all begin @code{gdb_}
+as in @code{gdb_use_file}.
+
+
+@heading Error Returns
+
+Libgdb functions that might not succeed generally have a return
+type of @code{gdb_error_t}.
+
+@deftypefun {const char *} gdb_error_msg (gdb_error_t @var{error})
+returns a reasonable error message for @var{error}.
+@end deftypefun
+
+
+@heading Blocking I/O
+
+[[[....]]]
+
+
+@heading Global Parameters
+@subheading the current directory
+@deftypefun gdb_error_t gdb_cd (char * @var{dir})
+Specify gdb's default directory as well as the working
+directory for the inferior (when first started).@*
+(cd_command)
+@end deftypefun
+
+@deftypefun {char *} gdb_copy_pwd ()
+Make a copy of the name of gdb's default directory.@*
+(pwd_command)
+@end deftypefun
+
+
+@subheading controlling the input/output radix
+@deftypefun gdb_error_t gdb_set_base (int)
+Change the default output radix to 10 or 16, or set it to 0
+(heuristic). This command is mostly obsolete now that the print
+command allows formats to apply to aggregates, but is still handy
+occasionally.@*
+(set_base_command)
+@end deftypefun
+
+@deftypefun gdb_error_t gdb_set_input_radix (int)
+@deftypefunx gdb_error_t gdb_set_output_radix (int)
+@deftypefunx gdb_error_t gdb_set_radix (int)
+Valid output radixes are only 0 (heuristic), 10, and 16.@*
+(set_radix)
+@end deftypefun
+
+
+@subheading manipulating environments
+@deftp Type {struct environ}
+@example
+struct environ
+@{
+ int allocated;
+ char ** vector;
+@}
+@end example
+A `struct environ' holds a description of environment
+variable bindings.
+@end deftp
+
+@deftypefun {struct environ *} gdb_make_environ ()
+Create a new (empty) environment.@*
+(make_environ)
+@end deftypefun
+
+@deftypefun {void} gdb_free_environ (struct environ *)
+Free an environment allocated by `gdb_make_environ'.@*
+(free_environ)
+@end deftypefun
+
+@deftypefun {void} gdb_init_environ (struct environ * env)
+Copy the processes environment into ENV.@*
+(init_environ)
+@end deftypefun
+
+@deftypefun {char **} gdb_get_in_environ (const struct environ * @var{env}, const char * @var{var})
+Look up the binding of @var{var} in @var{env}.@*
+(get_in_environ)
+@end deftypefun
+
+
+@deftypefun {void} gdb_set_in_environ (struct environ * @var{env}, const char * @var{var}, const char * @var{value})
+Lookup/bind variables within an environment.
+(set_in_environ)
+@end deftypefun
+
+
+@subheading legal notices
+@deftypefun {char **} gdb_copying ()
+@deftypefunx {char **} gdb_warranty ()
+These return pointers to NULL terminated arrays of strings.
+They contain text which describes the conditions under which
+libgdb is distributed (`gdb_copying') and which explains to
+users that there is no warranty for libgdb (`gdb_warranty').@*
+(show_warranty_command, show_copying_command)
+@end deftypefun
+
+
+@subheading the inferior's terminal
+@deftypefun void gdb_inferiors_io (int @var{std_in}, int @var{std_out}, int @var{std_err})
+Assert that the given descriptors should be copied into
+descriptors 0, 1, and 2 of the inferior when it
+is next run.
+@end deftypefun
+
+
+@heading callbacks
+
+One idiom used in several places deserves mention.
+At times, it makes sense for libgdb functions to
+invoke functions provided by the libgdb client.
+Where this is the case, callback structures are used
+to refer to client functions. For example, here
+are the declarations for a callback to which libgdb
+will pass an integer and a character pointer.
+
+@example
+struct a_gdb_cback;
+typedef void (*a_gdb_cback_fn) (struct a_gdb_cback *,
+ int, char *);
+@end example
+
+Suppose the client wants the callback to be implemented
+by @code{foo} which we will assume takes not only the integer
+and character pointer, but also a floating point number.
+The client could use these declarations:
+
+@example
+struct my_cback
+@{
+ struct a_gdb_cback gdb_cback; /* must be first */
+ float magic_number;
+@};
+
+void
+foo_helper (struct a_gdb_cback * callback, int i, char * cp)
+@{
+ foo ( ((struct my_cback *)callback)->magic_number, i, c);
+@}
+
+struct my_cback
+@{
+ foo_helper,
+ 1079252848.8
+@} the_cback;
+@end example
+
+
+@subheading stream callbacks
+
+A common kind of callback takes just a character pointer,
+presumed to point to part or all of an informational
+message.
+
+@example
+struct gdb_stream_cback;
+typedef void (*gdb_stream_cback_fn) (struct gdb_stream_cback *,
+ char *);
+@end example
+
+
+@subheading integer callbacks
+
+Another common kind of callback takes just an integer.
+
+@example
+struct gdb_int_cback;
+typedef void (*gdb_int_cback_fn) (struct gdb_int_cback *, int);
+@end example
+
+@node Targets, Symtabs, Conventions, top
+@comment node-name, next, previous, up
+@chapter Selecting Targets and Symbol Tables for Debugging
+@cindex targets
+
+@deftypefun gdb_error_t gdb_use_file (char * @var{filename})
+Arrange to read both executable code and symbol table information
+from FILENAME.
+
+This is exactly equivalent to a sequence of two calls:
+@example
+ gdb_use_exec_file (filename);
+ gdb_use_symbol_file (filename);
+@end example
+(file_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_use_exec_file (char * @var{filename})
+Read the code to debug from `filename'.@*
+(exec_file_command)
+@end deftypefun
+
+
+@deftypefun {char *} gdb_get_exec_file ()
+Return the name of the executable file as a string or 0
+if there is none.
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_use_core (char * @var{filename})
+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; GDB
+can access the executable file itself for other parts.
+
+If @var{filename} is @code{NULL}, no core file is used.@*
+(core_file_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_use_symbol_file (char * @var{filename})
+Arrange to read symbol table information from `filename'.
+
+This is the same as:
+
+ gdb_symbol_file_add (filename, 1, (CORE_ADDR)0, 1, 0, 0);
+
+See @code{gdb_symbol_file_add} for finer control over the symbol
+table.@*
+(symbol_file_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_symbol_file_add (@var{name}, @var{verbose}, @var{text_addr}, @var{replace}, @var{eager})
+Arrange to read additional symbol table information from
+the file `name'.
+
+The arguments are:
+@itemize @minus
+@item struct gdb_stream_cback * @var{info_out}
+
+Callback to handle informational output.
+
+@item char * @var{name}
+
+If not 0, verbose output will occur.
+
+@item int @var{be_verbose}
+
+Regulates the amount of informational output produced.
+
+@item CORE_ADDR @var{text_addr}
+
+is the address at which the named file is presumed to have
+been loaded.
+
+@item int @var{replace}@*
+
+If not 0, this will become the only file
+in the symbol table -- all previously loaded
+symbol table information will be discarded.
+
+@item int @var{readnow}
+
+If not 0, eagerly read symbols from this file,otherwise
+symbols will only be read lazily (as needed).
+@end itemize
+@end deftypefun
+
+
+@deftypefun {char *} gdb_copy_exec_path ()
+Make a copy of the execution path.@*
+[[[implement: strsave(get_in_environ (inferior_environ, "PATH"));]]]@*
+(path_info)
+@end deftypefun
+
+
+@deftypefun void gdb_mod_exec_path (char * @var{dirnames})
+Add zero or more directories to the front of the execution path.
+@var{dirnames} should be a colon separated list of directory names.@*
+(path_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_target_device (char * @var{name})
+Connects the libgdb host environment to a target machine
+or process.@*
+(target foo)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_set_baud (int @var{rate})
+If using a remote target connected by a serial port,
+use RATE as the communication speed.
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_set_target_debugging (int @var{level})
+Choose the level of verboseness of with which a remote
+target produces debugging output.
+@end deftypefun
+
+@node Symtabs, Source, Targets, top
+@comment node-name, next, previous, up
+@chapter Accessing symbol tables and debugging information.
+@cindex Symtabs
+@cindex {Symbol Tables}
+
+@deftp Type {struct symtab}
+Each source file is represented by a struct symtab.
+In many contexts, @code{struct symtab *} is used in preference
+to a {char *} filename to refer to the source.
+@end deftp
+
+
+@deftypefun {char *} gdb_symtab_to_filename (struct symtab *)
+@deftypefunx {char *} gdb_symtab_to_dirname (struct symtab *)
+Return the location of the file corresponding to this symtab.
+@code{gdb_symtab_to_dirname} might return @code{NULL} if no directory
+is known. @code{gdb_symtab_to_line_count} might return -1 if line
+number information is unavailable.
+@end deftypefun
+
+@deftypefun int gdb_symtab_to_line_count (struct symtab *)
+(See also `Source')
+@end deftypefun
+
+
+@deftypefun {struct symtab *} gdb_filename_to_symtab (char * @var{filename})
+Lookup the symbol table of a source file named NAME.@*
+(lookup_symtab)
+@end deftypefun
+
+
+@deftp Type {struct symtab_and_line}
+@example
+struct symtab_and_line
+@{
+ struct symtab *symtab;
+ int line;
+ CORE_ADDR pc;
+ CORE_ADDR end;
+@}
+@end example
+
+@code{struct symtab_and_line} is used to refer to a particular line
+of source code. It is used to locate breakpoints in the source
+code and the executable.
+
+@code{line} starts at 1 and proceeds through symtab->nlines.
+0 is never a valid line number; it is used to indicate
+that line number information is not available.
+@end deftp
+
+
+@deftypefun {struct symtab_and_line} gdb_find_pc_line (CORE_ADDR @var{pc}, int @var{notcurrent})
+Find the source file and line number for a given @var{pc} value.
+Return a structure containing a symtab pointer, a line number,
+and a pc range for the entire source line.
+The value's @code{.pc} field is NOT the specified @var{pc}.
+@var{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.@*
+(find_pc_line)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_find_line (struct symtab_and_line * @var{out}, struct symtab *, int)
+Create a symtab_and_line for a given symtab and line number.
+In other words, if you know the source file and line,
+this returns a location for the breakpoint.@*
+(resolve_sal_pc)
+@end deftypefun
+
+
+@deftypefun {struct symtabs_and_lines} gdb_decode_line (@var{argptr}, @var{firstln}, @var{default_symtab}, @var{default_line}, @var{canonical})
+@example
+ char ** argptr;
+ int funfirstline;
+ struct symtab * default_symtab;
+ int default_line;
+ char *** canonical;
+@end example
+ Parse a string that specifies a line number in GDB syntax.
+ @var{argptr} 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.
+
+ The return value of this function includes allocated memory
+ which the caller is responsible for freeing:
+
+ struct symtabs_and_lines sals;
+ sals = decode_line_spec (arg, 1);
+ ....
+ free (sals.sals);@*
+(decode_line_1)
+@end deftypefun
+
+
+@deftp Type {struct block *}
+Lexical environments in the program are represented by struct block.
+These are useful as arguements to expression parsing functions (see
+`Expressions').
+@end deftp
+
+
+@deftypefun {struct block *} gdb_block_for_pc (CORE_ADDR)
+Return the innermost lexical block containing the
+specified pc value, or 0 if there is none.@*
+(block_for_pc)
+@end deftypefun
+
+
+@deftypefun {struct block *} gdb_get_frame_block (FRAME @var{frame})
+This returns the block being executed by a given
+stack frame (see `Stack')@*
+(get_frame_block)
+@end deftypefun
+
+
+@deftypefun int gdb_find_line_pc_range (@var{syms}, @var{line}, @var{start_out}, @var{end_out})
+@example
+struct symtab * @var{start_out};
+int @var{line};
+CORE_ADDR * @var{start_out};
+CORE_ADDR * @var{end_out};
+@end example
+Find the range of pc values in a line.@*
+Store the starting pc of the line into @code{*@var{startptr}}.
+and the ending pc (start of next line) into @code{*@var{endptr}}.
+
+Returns 1 to indicate success.@*
+Returns 0 if could not find the specified line.@*
+(find_line_pc_range)
+@end deftypefun
+
+
+@deftypefun int gdb_find_pc_partial_function (@var{pc}, @var{name}, @var{address}, @var{endaddr})
+@example
+CORE_ADDR @var{pc};
+char **@var{name};
+CORE_ADDR *@var{address};
+CORE_ADDR *@var{endaddr};
+@end example
+Finds the "function" (text symbol) that is smaller than @var{pc} but
+greatest of all of the potential text symbols. Sets @code{*@var{name}}
+and/or @code{*@var{address}} conditionally if that pointer is non-null. If
+@var{endaddr} is non-null, then set @code{*@var{endaddr}} to be the end of
+the function (exclusive), but passing @var{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
+@code{*@var{name}}, @code{*@var{address}}, and @code{*@var{endaddr}} to
+real information and returns 1. If it fails, it sets @code{*@var{name}},
+@code{*@var{address}}, and @code{*@var{endaddr}} to zero and returns 0.
+
+@example
+ 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");
+@end example
+(find_pc_partial_function)
+@end deftypefun
+
+
+@deftypefun void gdb_list_symbols (@var{info_out}, @var{regexp}, @var{class}, @var{bpt})
+@example
+struct gdb_stream_cback * @var{info_out};
+char * @var{regexp};
+int @var{class};
+int @var{bpt};
+@end example
+List all symbols (if @var{regexp} is NULL) or all symbols matching @var{regexp}.
+
+
+If @var{class} is ...
+@itemize @bullet
+@item
+0, list all symbols except functions, type names, and
+constants (enums).
+@item
+1, list only functions.
+@item
+2, list only type names.
+@item
+3, list only method names.
+@end itemize
+BPT is non-zero if set a breakpoint at the functions we find.@*
+(variables_info, functions_info, types_info, list_symbols)
+@end deftypefun
+
+
+@deftypefun int gdb_locals_info (struct gdb_stream_cback * @var{info_out}, FRAME @var{frame})
+Print all the local variables in the given 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 @var{frame}.@*
+(locals_info)
+@end deftypefun
+
+
+@deftypefun int print_frame_arg_vars (struct gdb_stream_cback *, FRAME)
+Similar to `gdb_locals_info'.@*
+(args_info)
+@end deftypefun
+
+@node Source, Running, Symtabs, top
+@comment node-name, next, previous, up
+@chapter Relating Inferiors to Source Files
+@cindex source
+@cindex {source files}
+
+How to find the source that corresponds to executable code and the
+executable code that corresponds to a line of source.
+
+@deftypefun {char *} gdb_copy_source_fullname (struct symtab *@var{s})
+Return a copy of the full path name to a source file.
+(See `Symtabs' for more information about filenames
+and symbol tables.).
+@end deftypefun
+
+
+@deftypefun int gdb_open_source_file (struct symtab *@var{s})
+Open a source file corresponding to @var{s}. Returns a file descriptor
+or negative number for error.
+[[[We may decide not to provide this function.]]]@*
+(open_source_file)
+@end deftypefun
+
+
+@deftypefun int gdb_source_line_pos (struct symtab * @var{s}, int @var{lineno})
+Return the byte offset of a given line of source
+or a negative number if @var{lineno} is out of range.@*
+(find_source_lines)
+@end deftypefun
+
+
+ -- IDIOM: The gdb command `show directories'.
+@example
+ puts_filtered ("Source directories searched: ");
+ puts_filtered (source_path);
+ puts_filtered ("\n");
+@end example
+(show_directories)
+
+
+@deftypefun {char *} gdb_source_path ()
+Return the path in which source files are sought.@*
+(source_path)
+@end deftypefun
+
+
+@deftypefun void gdb_modify_source_path (char * @var{dirnames})
+Change the source path according to dirnames.@*
+(directory_command)
+@end deftypefun
+
+
+See `Symtabs' for functions relating symbol tables to files.
+(source_info)
+
+
+See `Symtabs' for functions relating source lines to PC values.
+(line_info)
+
+
+[[[Try to expose sources_info without having to introduce struct object *?]]]
+(sources_info)
+
+
+@node Running, Stopping, Source, top
+@comment node-name, next, previous, up
+@chapter Creating, Continuing, and Stepping Through an Inferior Process
+@cindex running
+
+
+@deftypefun gdb_error_t gdb_target_create_inferior (@var{exec}, @var{args}, @var{environ})
+@example
+char * @var{exec_file};
+char * @var{inferior_args};
+char ** @var{inferior_environment_vector};
+@end example
+Create a running inferior.
+[[[I think the exec_file parameter is redundant. Perhaps this will take
+only two arguments.]]]@*
+(run_command, target_create_inferior)
+@end deftypefun
+
+
+@deftypefun int gdb_target_has_execution ()
+Return non-0 if an inferior is running.@*
+(target_has_execution)
+@end deftypefun
+
+
+@deftypefun void gdb_target_kill ()
+Kill the inferior process. Make it go away.
+The inferior may become a core file.
+If so, gdb_target_has_stack() will return non-0.@*
+(target_kill)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_step_1 (@var{skip_subs}, @var{single_inst}, @var{repeat_count})
+@example
+int skip_subs;
+int single_inst;
+int repeat_count;
+@end example
+Continue a program a little bit. Roughly:
+@example
+ for (; count > 0; --count)
+ gdb_clear_proceed_status ();
+ gdb_proceed (...);
+@end example
+(next_command, nexti_command, step_command, stepi_command)
+@end deftypefun
+
+
+ -- IDIOM: Continuing a program where it stopped.
+@example
+ gdb_clear_proceed_status ();
+ gdb_proceed ((CORE_ADDR) -1, -1, 0);
+@end example
+(continue_command)
+
+
+ -- IDIOM: Continuing a program giving it a specified signal.
+@example
+ gdb_clear_proceed_status ();
+ gdb_proceed ((CORE_ADDR) -1, signum, 0);
+@end example
+(signal_command)
+
+
+@deftypefun {char *} strtosigno (char * @var{str})
+(Typical use:)
+@example
+ signum = strtosigno (signum_exp);
+
+ if (signum == 0)
+ /* Not found as a name, try it as an expression. */
+ signum = parse_and_eval_address (signum_exp);
+
+ gdb_clear_proceed_status ();
+ gdb_proceed ();
+@end example
+@end deftypefun
+
+
+ -- IDIOM: Continuing a program at a specified address.
+@example
+ gdb_clear_proceed_status ();
+ gdb_proceed (addr, 0, 0);
+@end example
+(jump_command)
+
+
+@deftypefun gdb_error_t gdb_finish ()
+"finish": Set a temporary breakpoint at the place
+the selected frame will return to, then continue.
+This is a convenience function but it summarizes a lot
+of other stuff.@*
+(finish_command)
+@end deftypefun
+
+
+@deftypefun void gdb_clear_proceed_status ()
+Clear out all variables saying what to do when inferior is continued.
+First do this, then set the ones you want, then call @code{gdb_proceed}.
+
+ [[[Some of these should be documented, others hidden.]]]
+@example
+ The variables are:
+ 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);
+@end example
+(clear_proceed_status)
+@end deftypefun
+
+
+@deftypefun void gdb_proceed (CORE_ADDR @var{addr}, int @var{signal}, int @var{step})
+Basic routine for continuing the program in various fashions.
+
+@var{addr} is the address to resume at, or -1 for resume where stopped.@*
+@var{signal} is the signal to give it, or 0 for none,
+or -1 for act according to how it stopped.@*
+@var{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 @code{gdb_clear_proceed_status} before calling proceed.
+(See the documentation for @code{gdb_clear_proceed_status} for more
+parameters to @code{gdb_proceed}).@*
+(proceed)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_return (value @var{return_value}, FRAME @var{frame})
+Make @var{frame} return to @var{value} to it's caller.
+Unlike the other functions in this section, this doesn't
+call proceed.
+(return_command)
+@end deftypefun
+
+
+@deftypefun int gdb_inferior_pid ()
+0 or the valid pid of an inferior.
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_attach (int @var{pid})
+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.@*
+(attach_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_detach (int @var{signal_num})
+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).@*
+(detach_command)
+@end deftypefun
+
+@node Stopping, Stack, Running, top
+@comment node-name, next, previous, up
+@chapter Using Breakpoints, Signaling an Inferior
+@cindex stopping
+@cindex breakpoints
+
+
+@deftp Type {struct breakpoint}
+Breakpoints are typically represented @code{struct breakpoint *}.
+@end deftp
+
+
+@deftypefun {struct breakpoint *} gdb_find_breakpoint (int)
+Find a breakpoint given it's number (return 0 if it doesn't exist).
+@end deftypefun
+
+@deftypefun gdb_error_t gdb_set_break (struct breakpoint * @var{brk_out}, struct symtab_and_line)
+@deftypefunx gdb_error_t gdb_set_tbreak (struct breakpoint *, struct symtab_and_line)
+@deftypefunx gdb_error_t gdb_set_until (struct breakpoint *, struct symtab_and_line)
+These three are like their command language counterparts.
+They are front ends to `gdb_set_raw_breakpoint'.
+See `Symtabs' for sources of `struct symtab_and_line'.@*
+(break_command, break_command_1, until_command, tbreak_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_set_watchpt (@var{brk_out}, @var{exp_string}, @var{exp}, @var{exp_valid_block})
+@example
+struct breakpoint * @var{brk_out};
+char * @var{exp_string};
+struct expression * @var{exp};
+struct block * @var{expression_valid_block};
+@end example
+Set a watchpoint for the given expression.@*
+(watch_command)
+@end deftypefun
+
+
+@deftypefun void gdb_set_ignore_count (int @var{bptnum}, int @var{count})
+Set ignore-count of breakpoint number BPTNUM to COUNT.@*
+(set_ignore_count)
+@end deftypefun
+
+
+@deftypefun {struct gdb_bp_condition *} gdb_set_condition (@var{bp}, @var{exp_str}, @var{cond})
+@example
+int @var{pbtnum};
+char * @var{exp_str};
+struct gdb_bp_condition * @var{cond};
+
+typedef int (*gdb_bp_fn) (struct gdb_bp_condition *, int bp_num);
+struct gdb_bp_condition
+@{
+ gdb_bp_fn fn;
+@};
+@end example
+Add a condition to a breakpoint.
+The condition is a callback which should return
+0 to skip the breakpoint, and 1 to break at it.
+It is called at times when the break might occur.
+
+A useful application of these callbacks to attach
+an expression to breakpoints like the gdb `condition'
+command. See `Expressions' for the parsing and
+evaluation of expressions.@*
+(condition_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_enable_breakpoint (struct breakpoint * @var{bpt}, int @var{once})
+@deftypefunx gdb_error_t gdb_disable_breakpoint (struct breakpoint * @var{bpt})
+Enable/disable a breakpoint. If `once' is not 0, the
+breakpoint is only temporarily enabled.@*
+(enable_breakpoint, disable_breakpoint, enable_command)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_delete_breakpoint (struct breakpoint * @var{bpt})
+Delete a breakpoint and clean up all traces of it in the
+data structures.@*
+(delete_breakpoint)
+@end deftypefun
+
+
+@deftypefun void gdb_clear_breakpoints (struct symtabs_and_lines * @var{sals})
+Clear breakpoints from a list of program locations as
+might be returned by `gdb_decode_line' (see `Symtabs').@*
+(clear_command)
+@end deftypefun
+
+
+@deftypefun {static struct symtabs_and_lines} get_catch_sals (int @var{this_level_only})
+Return the line numbers of all exception handlers currently
+active (or `this_level_only'?? [[[?]]]).
+[[[The implementation should remember to resolve_sal_pc]]]
+@end deftypefun
+
+
+@deftp Type {struct breakpoint_cback}
+@example
+typedef void (*breakpoint_cback_fn) (struct breakpoint_cback *, int bp_num);
+struct breakpoint_cback
+@{
+ breakpoint_cback_fn fn;
+@};
+@end example
+
+Breakpoints can have an associated function which is called
+when the program is stopped by that breakpoint.@*
+(commands_command)
+@end deftp
+
+
+@deftypefun {struct breakpoint_cback *} gdb_set_breakpoint_cback (int @var{bp_num}, struct breakpoint_cback *)
+This sets a breakpoint callback and returns the previous callback value
+for that breakpoint.
+[[[In the long run, the command interpreter should be available
+ for the use of hooks like this one.]]]
+@end deftypefun
+
+
+@deftypefun {struct breakpoint_cback *} gdb_get_breakpoint_cback (int @var{bp_num})
+@end deftypefun
+
+
+@deftypefun void gdb_breakpoints_info (struct gdb_stream_cback, int @var{bp_num}, int @var{watches})
+Print information on breakpoint number @var{bnum}, or -1 if all.
+If @var{watches} is zero, process only breakpoints; if @var{watches}
+is nonzero, process only watchpoints.
+[[[In the long run, expose the information read off by this function.]]]@*
+(info breakpoints, info watchpoints, breakpoints_info, breakpoint_1)
+@end deftypefun
+
+
+@deftypefun void gdb_catch_info (struct gdb_stream_cback *)
+Print a list of all the exception handlers that are active in the
+current stack frame at the current point of execution.@*
+(catch_info)
+@end deftypefun
+
+
+@deftypefun void gdb_handle_command (char * @var{args})
+Takes arguments like the gdb command `handle' and has
+the same effect.@*
+(handle_command)
+@end deftypefun
+
+
+@deftypefun void gdb_signals_info (struct gdb_stream_cback *)
+Show how signals are handled.@*
+(signals_info)
+@end deftypefun
+
+
+@node Stack, Expressions, Stopping, top
+@comment node-name, next, previous, up
+@chapter Accessing An Inferior's Execution Stack
+@cindex stack
+@cindex FRAME
+@cindex {stack frames}
+
+
+
+@deftp Type FRAME
+This type representing active stack frames in the inferior.
+Consider this type opaque.
+@end deftp
+
+
+@deftypefun FRAME gdb_get_innermost_frame ()
+Returns the innermost frame or the frame most recently designated
+as current by a call to gdb_set_current_frame.@*
+(get_current_frame)
+@end deftypefun
+
+
+@deftypefun FRAME gdb_get_caller_frame (FRAME @var{frame})
+Return the frame that called @var{frame}.@*
+If @var{frame} is the original frame (it has no caller), return 0.@*
+(get_prev_frame)
+@end deftypefun
+
+
+@deftypefun FRAME gdb_get_called_frame (FRAME @var{frame})
+Return the frame that @var{frame} calls (0 if @var{frame} is the innermost
+frame).@*
+(get_next_frame)
+@end deftypefun
+
+
+@deftypefun FRAME gdb_parse_frame_specification (char * @var{frame_exp})
+Read a frame specification in whatever the appropriate format is.
+Call @code{error}() If the specification is in any way invalid (i.e.
+this function never returns NULL).@*
+(parse_frame_specification)
+@end deftypefun
+
+
+@deftypefun CORE_ADDR get_frame_pc (FRAME @var{frame})@*
+(Example use: Implementing @code{disassemble_command})@*
+(get_frame_pc)
+@end deftypefun
+
+
+@deftypefun FRAME gdb_selected_frame ()
+The "selected" stack frame is used by default for local and
+arg access. May be @code{NULL}, for no selected frame.@*
+(variable selected_frame)
+@end deftypefun
+
+
+@deftypefun int gdb_selected_frame_level ()
+Level of the selected frame:@*
+0 for innermost,@*
+1 for its caller,@*
+or -1 for frame specified by address with no defined level.@*
+(variable selected_frame_level)
+@end deftypefun
+
+
+@deftypefun void gdb_select_frame (FRAME @var{frame}, int @var{level})
+Select frame @var{frame}, and note that its stack level is @var{level}.
+@var{level} may be -1 if an actual level number is not known.
+Calls @code{set_language} to establish the correct language for the
+selected frame.
+@end deftypefun
+
+
+ -- IDIOM: Computing Frame Levels@*
+@example
+/* Try to figure out what level this frame is as before a
+ call to gdb_select_frame. But if there is
+ no current stack, don't error out, just pass -1
+ instead. */
+frame1 = 0;
+level = -1;
+if (get_current_frame()) @{
+ for (frame1 = get_prev_frame (0);
+ frame1 && frame1 != frame;
+ frame1 = get_prev_frame (frame1))
+ level++;
+@}
+@end example
+
+
+@deftypefun void gdb_print_stack_frame (@var{cback}, @var{frame}, @var{level}, @var{source})
+@example
+struct gdb_stream_cback * @var{cback};
+FRAME @var{frame};
+int @var{level};
+int @var{source};
+@end example
+Print a stack frame briefly. @var{frame} should be the frame id
+and @var{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 @var{source} is 1, print the source line as well.@*
+If @var{source} is -1, print ONLY the source line.@*
+(print_stack_frame)
+@end deftypefun
+
+
+@deftypefun void gdb_print_backtrace (cback, @var{count}, @var{from_tty})
+@example
+struct gdb_stream_cback * @var{cback};
+int @var{count};
+int @var{from_tty};
+@end example
+Print briefly all stack frames or just the innermost @var{count} frames.@*
+(backtrace_command)
+@end deftypefun
+
+
+@deftypefun FRAME gdb_find_relative_frame (FRAME @var{frame}, int * @var{level_offset_ptr})
+Find a frame a certain number of levels away from @var{frame}.
+@var{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 @var{*level_offset_ptr} is nonzero and indicates
+how much farther the original request asked to go.
+@end deftypefun
+
+
+@deftypefun FRAME gdb_select_frame_downward (int @var{count})
+@deftypefunx FRAME gdb_select_frame_upward (int @var{count})
+Simply a combination of find_relative_frame and select_frame.
+Returns the newly selected frame.@*
+(down_silently_command, up_silently_command)
+@end deftypefun
+
+
+@deftypefun void gdb_frame_info (struct gdb_stream_cback * @var{cback}, FRAME @var{frame})
+Print verbosely the selected the argument @var{frame}.
+This means absolutely all information in the frame is printed.@*
+(frame_info)
+@end deftypefun
+
+
+@node Expressions, Values, Stack, top
+@comment node-name, next, previous, up
+@chapter How to Parse and Evaluate Expressions
+@cindex parsing
+@cindex expressions
+@cindex {expression evaluation}
+@cindex evaluation
+
+
+@deftp Type {struct expression *}
+This represents a parsed expression as might be used for a
+breakpoint condition.
+@end deftp
+
+
+@deftp Type {struct block}
+Describes a lexical environment.
+@end deftp
+
+See also `Values'
+See also `Examining'
+
+
+@deftypefun struct expression * parse_exp_1 (char ** @var{stringptr}, struct block * @var{block} int @var{comma})
+Read an expression from the string @code{*@var{stringptr}} points to,
+parse it, and return a pointer to a struct expression that we malloc.
+Use @var{block} as the lexical context for variable names;
+if @var{block} is zero, use the block of the selected stack frame.
+Meanwhile, advance @code{*@var{stringptr}} to point after the expression,
+at the first nonwhite character that is not part of the expression
+(possibly a null character).
+
+If @var{comma} is nonzero, stop if a comma is reached.
+(See `Stack' for information about the selected frame)
+@end deftypefun
+
+
+@deftypefun gdb_error_t gdb_evaluate_expression (value * @var{value_out}, struct expression * @var{exp})
+Evaluate an expression. See `values' for more information about
+the return type.@*
+(evaluate_expression)
+@end deftypefun
+
+
+@deftypefun value gdb_evaluate_type (struct expression @var{*exp})
+Evaluate an expression, avoiding all memory references
+and getting a value whose type alone is correct.@*
+(evaluate_type)
+@end deftypefun
+
+
+
+@node Values, Examining, Expressions, top
+@comment node-name, next, previous, up
+@chapter Data from the Inferior, the Values of Expressions
+@cindex values
+@cindex {expression values}
+
+Values are allocated by functions such as @code{gdb_evaluate_expression}.
+All currently allocated values are on the list @code{all_values} and can be
+freed by calling @code{gdb_free_all_values}.
+
+To preserve a value across calls to @code{gdb_free_all_values}, use
+@code{gdb_release_value}. Values added to the history list are automaticly
+released. To free a released value use @code{gdb_free_value}.
+
+
+@deftypefun void gdb_free_value (value)
+Free the memory associated with a released value.
+Do not call this function except on values that have been
+passed to @code{gdb_release_value}.@*
+(gdb_value_free)
+@end deftypefun
+
+
+@deftypefun void gdb_free_all_values (void)
+Free all allocated values which haven't been released.
+This should be called periodically from outside the dynamic
+scope of libgdb functions.@*
+(free_all_values)
+@end deftypefun
+
+
+@deftypefun void gdb_release_value (value @var{val})
+Remove a value from the list @code{all_values} in order to
+protect it from @code{gdb_free_all_values}.@*
+(release_value)
+@end deftypefun
+
+
+There is a `history list' -- a numbered list of values for
+future reference. These can be referred to in expressions,
+for example.
+
+@deftypefun int gdb_record_latest_value (value @var{val})
+Add a value to the history list.@*
+(record_latest_value)
+@end deftypefun
+
+
+@deftypefun value gdb_access_value_history (int @var{index})
+Retrieve a value from the history list.@*
+(access_value_history)
+@end deftypefun
+
+
+[[[At the moment, the only libgdb use for values is
+ string formatting (see `Examining'). So, they are treated
+ as opaque. It'd be useful to expose more of them in the long run.]]]
+
+
+@node Examining, Types, Values, top
+@comment node-name, next, previous, up
+@chapter Formatting Values as Strings
+@cindex examining
+@cindex printing
+@cindex formatting
+@cindex {pretty printing}
+
+
+Many functions in this section use @code{struct gdb_stream_cback}.
+That structure is explained in `Basics'.
+
+
+@deftypefun void gdb_print_formatted (struct gdb_stream_cback * @var{cback}, value @var{val}, int @var{format}, int @var{size})
+Print value @var{val} on a stream according to @var{format}, a letter or 0.
+Do not end with a newline.
+0 means print @var{val} according to its own type.
+@var{size} is the letter for the size of datum being printed.
+This is used to pad hex numbers so they line up.@*
+(print_formatted)
+@end deftypefun
+
+
+@deftypefun static void gdb_printf_command (struct gdb_stream_cback * @var{cback}, char * @var{format}, value * @var{values}, int @var{n_values})@*
+(printf_command)
+@end deftypefun
+
+
+@deftypefun int gdb_value_print (struct gdb_stream_cback * @var{cback}, @var{value}, int @var{format}, enum @var{val_prettyprint})
+Print the value @var{val} in C-ish syntax on @var{stream}.
+@var{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.
+[[[implementation: watch the change in argument order]]]@*
+(value_print)
+@end deftypefun
+
+
+ -- IDIOM: This prints the values of all convenience variables:
+@example
+for (var = internalvars; var; var = var->next)
+@{
+printf_filtered ("$%s = ", var->name);
+value_print (var->value, stdout, 0, Val_pretty_default);
+printf_filtered ("\n");
+@}
+@end example
+
+
+@deftypefun int gdb_print_insn (struct gdb_stream_cback * @var{cback}, CORE_ADDR @var{memaddr})
+Print the instruction at @var{memaddr} and return the
+length of the instruction in bytes.@*
+(print_insn)
+@end deftypefun
+
+
+@deftypefun void gdb_print_address (struct gdb_stream_cback * @var{cback}, CORE_ADDR @var{addr})
+Print address @var{addr} symbolically on @var{stream}.
+First print it as a number. Then perhaps print
+@code{<SYMBOL + OFFSET>} after the number.@*
+(print_address)
+@end deftypefun
+
+
+ -- IDIOM: This is the core of a dissasemble command:
+@example
+for (pc = low; pc < high; )
+@{
+ print_address (pc, stdout);
+ printf_filtered (":\t");
+ pc += print_insn (pc, stdout);
+ printf_filtered ("\n");
+@}
+@end example
+Advice for computing pc extents like @code{low} and @code{high}
+can be found in `Symtabs' -- for example, @code{gdb_find_line_pc_range}.@*
+(disassemble_command)
+
+
+@deftypefun void gdb_print_registers (struct gdb_stream_cback * @var{cback}, int @var{regnum}, int @var{fpregs}, int @var{fancy})
+Print the values of registers.
+@var{regnum} can be -1 (print all the registers) or a specific register number.
+If @var{regnum} is -1, @var{fpregs} determines whether floating point registers are
+shown.@*
+(info registers, info all-registers, nofp_registers_info, all_registers_info)
+@end deftypefun
+
+
+@deftypefun char * gdb_register_name (int @var{i})
+Look up a register name by number.
+@end deftypefun
+
+
+@deftypefun int gdb_parse_register_name (char ** @var{name})
+Parse a register name and advance a text pointer.
+Return -1 for bogus names.
+@end deftypefun
+
+
+@deftypefun CORE_ADDR gdb_read_pc ()
+Return the contents of the inferior's program counter.
+@end deftypefun
+
+
+@deftypefun int gdb_is_stepping ()
+If true, the inferior is stopped after being stepped.
+@end deftypefun
+
+
+@deftypefun void gdb_current_breakpoints (gdb_int_cback)
+Call a callback for each of the current breakpoints.@*
+(program_info)
+@end deftypefun
+
+
+@deftypefun int gdb_stop_signal ()
+Return the signal that stopped the inferior.
+@end deftypefun
+
+
+@deftypefun char * strsigno (int)
+Return a symbolic name for a signal.
+@end deftypefun
+
+
+@deftypefun void gdb_target_info (struct gdb_stream_cback *)
+Print status information about target we're accessing.@*
+(target_files_info, e.g. child_files_info)
+@end deftypefun
+
+
+float_info
+[[[what is appropriate?]]]
+
+
+@deftypefun void gdb_address_info (struct gdb_stream_cback * @var{cback}, char * @var{symbol});
+Like the `info address' command -- show where @var{symbol}
+is located.@*
+(address_info)
+@end deftypefun
+
+
+@node Types, top, Examining, top
+@comment node-name, next, previous, up
+@chapter Examining the Types of an Inferior's Data
+@cindex types
+
+
+@deftp Type {struct type}
+@code{struct type *} is used to represent a type. For example, that is
+the type returned by the macro @code{VALUE_TYPE(val)} which yields the
+type of inferior data recorded in @code{val}. (see `evaluate_type' in
+`Expressions').
+@end deftp
+
+
+@deftypefun void type_print (@var{type}, @var{varstring}, @var{stream_cback}, @var{show})
+@example
+struct type @var{*type};
+char @var{*varstring};
+struct gdb_stream_cback * @var{stream_cback};
+FILE @var{*stream};
+int @var{show};
+@end example
+Print a description of a type @var{type} in the form of a declaration of a
+variable named @var{varstring}. (@var{varstring} is demangled if necessary.)
+Output goes to @var{stream_cback}.
+
+If @var{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 @var{show} is negative, we never show the details of elements' types.
+(See `Basics' for an explanation of `struct gdb_stream_cback').
+@end deftypefun
+
+
+[[[In the long run, we need something to programmaticly read off type
+ structures in a machine/language independent way.]]]
+
+@bye
diff --git a/gnu/usr.bin/gdb/doc/lpsrc.sed b/gnu/usr.bin/gdb/doc/lpsrc.sed
new file mode 100644
index 0000000..1c7af4a
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/lpsrc.sed
@@ -0,0 +1,13 @@
+/font defs: ---/,/end font defs ---/c\
+%-------------------- PostScript (long names) font defs: -----------------\
+\\font\\bbf=Times-Bold at 10pt\
+\\font\\vbbf=Times-Bold at 12pt\
+\\font\\smrm=Times-Roman at 6pt\
+\\font\\brm=Times-Roman at 10pt\
+\\font\\rm=Times-Roman at 8pt\
+\\font\\it=Times-Italic at 8pt\
+\\font\\tt=Courier at 8pt\
+% Used only for \copyright, replacing plain TeX macro.\
+\\font\\sym=Symbol at 7pt\
+\\def\\copyright{{\\sym\\char'323}}\
+%-------------------- end font defs ---------------------------------
diff --git a/gnu/usr.bin/gdb/doc/psrc.sed b/gnu/usr.bin/gdb/doc/psrc.sed
new file mode 100644
index 0000000..9bb557e
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/psrc.sed
@@ -0,0 +1,13 @@
+/font defs: ---/,/end font defs ---/c\
+%-------------------- PostScript (K Berry names) font defs: --------------\
+\\font\\bbf=ptmb at 10pt\
+\\font\\vbbf=ptmb at 12pt\
+\\font\\smrm=ptmr at 6pt\
+\\font\\brm=ptmr at 10pt\
+\\font\\rm=ptmr at 8pt\
+\\font\\it=ptmri at 8pt\
+\\font\\tt=pcrr at 8pt\
+% Used only for \copyright, replacing plain TeX macro.\
+\\font\\sym=psyr at 7pt\
+\\def\\copyright{{\\sym\\char'323}}\
+%-------------------- end font defs ---------------------------------
diff --git a/gnu/usr.bin/gdb/doc/refcard.ps b/gnu/usr.bin/gdb/doc/refcard.ps
new file mode 100644
index 0000000..0046b79
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/refcard.ps
@@ -0,0 +1,798 @@
+%!PS-Adobe-2.0
+%%Creator: dvips 5.47 Copyright 1986-91 Radical Eye Software
+%%Title: refcard.dvi
+%%Pages: 2 1
+%%BoundingBox: 0 0 612 792
+%%EndComments
+%%BeginProcSet: tex.pro
+/TeXDict 200 dict def TeXDict begin /N /def load def /B{bind def}N /S /exch
+load def /X{S N}B /TR /translate load N /isls false N /vsize 10 N /@rigin{
+isls{[0 1 -1 0 0 0]concat}if 72 Resolution div 72 VResolution div neg scale
+Resolution VResolution vsize neg mul TR matrix currentmatrix dup dup 4 get
+round 4 exch put dup dup 5 get round 5 exch put setmatrix}N /@letter{/vsize 10
+N}B /@landscape{/isls true N /vsize -1 N}B /@a4{/vsize 10.6929133858 N}B /@a3{
+/vsize 15.5531 N}B /@ledger{/vsize 16 N}B /@legal{/vsize 13 N}B /@manualfeed{
+statusdict /manualfeed true put}B /@copies{/#copies X}B /FMat[1 0 0 -1 0 0]N
+/FBB[0 0 0 0]N /nn 0 N /IE 0 N /ctr 0 N /df-tail{/nn 8 dict N nn begin
+/FontType 3 N /FontMatrix fntrx N /FontBBox FBB N string /base X array
+/BitMaps X /BuildChar{CharBuilder}N /Encoding IE N end dup{/foo setfont}2
+array copy cvx N load 0 nn put /ctr 0 N[}B /df{/sf 1 N /fntrx FMat N df-tail}
+B /dfs{div /sf X /fntrx[sf 0 0 sf neg 0 0]N df-tail}B /E{pop nn dup definefont
+setfont}B /ch-width{ch-data dup length 5 sub get}B /ch-height{ch-data dup
+length 4 sub get}B /ch-xoff{128 ch-data dup length 3 sub get sub}B /ch-yoff{
+ch-data dup length 2 sub get 127 sub}B /ch-dx{ch-data dup length 1 sub get}B
+/ch-image{ch-data dup type /stringtype ne{ctr get /ctr ctr 1 add N}if}B /id 0
+N /rw 0 N /rc 0 N /gp 0 N /cp 0 N /G 0 N /sf 0 N /CharBuilder{save 3 1 roll S
+dup /base get 2 index get S /BitMaps get S get /ch-data X pop /ctr 0 N ch-dx 0
+ch-xoff ch-yoff ch-height sub ch-xoff ch-width add ch-yoff setcachedevice
+ch-width ch-height true[1 0 0 -1 -.1 ch-xoff sub ch-yoff .1 add]{ch-image}
+imagemask restore}B /D{/cc X dup type /stringtype ne{]}if nn /base get cc ctr
+put nn /BitMaps get S ctr S sf 1 ne{dup dup length 1 sub dup 2 index S get sf
+div put}if put /ctr ctr 1 add N}B /I{cc 1 add D}B /bop{userdict /bop-hook
+known{bop-hook}if /SI save N @rigin 0 0 moveto}N /eop{clear SI restore
+showpage userdict /eop-hook known{eop-hook}if}N /@start{userdict /start-hook
+known{start-hook}if /VResolution X /Resolution X 1000 div /DVImag X /IE 256
+array N 0 1 255{IE S 1 string dup 0 3 index put cvn put}for}N /p /show load N
+/RMat[1 0 0 -1 0 0]N /BDot 260 string N /rulex 0 N /ruley 0 N /v{/ruley X
+/rulex X V}B /V statusdict begin /product where{pop product dup length 7 ge{0
+7 getinterval(Display)eq}{pop false}ifelse}{false}ifelse end{{gsave TR -.1 -.1
+TR 1 1 scale rulex ruley false RMat{BDot}imagemask grestore}}{{gsave TR -.1
+-.1 TR rulex ruley scale 1 1 false RMat{BDot}imagemask grestore}}ifelse B /a{
+moveto}B /delta 0 N /tail{dup /delta X 0 rmoveto}B /M{S p delta add tail}B /b{
+S p tail}B /c{-4 M}B /d{-3 M}B /e{-2 M}B /f{-1 M}B /g{0 M}B /h{1 M}B /i{2 M}B
+/j{3 M}B /k{4 M}B /w{0 rmoveto}B /l{p -4 w}B /m{p -3 w}B /n{p -2 w}B /o{p -1 w
+}B /q{p 1 w}B /r{p 2 w}B /s{p 3 w}B /t{p 4 w}B /x{0 S rmoveto}B /y{3 2 roll p
+a}B /bos{/SS save N}B /eos{clear SS restore}B end
+%%EndProcSet
+TeXDict begin 1000 300 300 @start /Fa 3 104 df<0003FE0000000FFF8000003C01E000
+00F000780001C0001C00030000060006000003000C0000018018000000C018000000C030000000
+603000000060600000003060000000306000000030C000000018C000000018C000000018C00000
+0018C000000018C000000018C000000018C000000018C000000018600000003060000000306000
+0000303000000060300000006018000000C018000000C00C000001800600000300030000060001
+C0001C0000F0007800003C01E000000FFF80000003FE000025277E9D2A>13
+D<003C00E001C00180038003800380038003800380038003800380038003800380038003000700
+1C00F0001C00070003000380038003800380038003800380038003800380038003800380018001
+C000E0003C0E297D9E15>102 D<F0001C00070003000380038003800380038003800380038003
+800380038003800380018001C000E0003C00E001C0018003800380038003800380038003800380
+03800380038003800380030007001C00F0000E297D9E15>I E /Fb 1 59
+df<60F0F06004047C830C>58 D E /Fc 61 125 df<01F8000604000C0E00180E001800001800
+00180000FFFE001806001806001806001806001806001806001806001806001806001806001806
+007E1F801114809313>12 D<01FE00060E000C0E00180600180600180600180600FFFE00180600
+1806001806001806001806001806001806001806001806001806001806007E1F801114809313>
+I<4100E380618020802080208041004100820009097F9311>34 D<020002000F8032406220C210
+C270C270E220F2007F003FC00FE002E002704230E230C2308220426022C01F00020002000C187E
+9511>36 D<40E06020202040408003097D9309>39 D<01020408103020606040C0C0C0C0C0C0C0
+C0C0C040606020301008040201081E7E950D>I<80402010080C04060602030303030303030303
+03020606040C0810204080081E7E950D>I<006000006000006000006000006000006000006000
+006000006000006000FFFFF0FFFFF0006000006000006000006000006000006000006000006000
+00600000600014167E9119>43 D<40E06020202040408003097D8209>I<FFFF080280860B>I<40
+E04003037D8209>I<0010003000600060006000C000C000C00180018003000300030006000600
+06000C000C000C0018001800300030003000600060006000C000C0000C1D7E9511>I<0F0030C0
+606060604020C030C030C030C030C030C030C030C030C03040206060606030C00F000C137E9211
+>I<0C001C00EC000C000C000C000C000C000C000C000C000C000C000C000C000C000C000C00FF
+C00A137D9211>I<1F0060C06060F070F030603000700070006000C001C0018002000400081010
+1020207FE0FFE00C137E9211>I<40E0400000000000000040E040030D7D8C09>58
+D<40E0400000000000000040E06020202040408003137D8C09>I<003000003000007800007800
+007800009C00009C00011E00010E00010E0002070002070004038007FF800403800801C00801C0
+1000E03800E0FE07FC16147F9319>65 D<FFFC001C07001C03801C01C01C01C01C01C01C01C01C
+03801C07001FFE001C03801C01C01C00E01C00E01C00E01C00E01C00E01C01C01C0380FFFE0013
+147F9317>I<00FC200703600C00E0180060300060700020600020E00000E00000E00000E00000
+E00000E000006000207000203000201800400C008007030000FC0013147E9318>I<FFFC001C07
+001C01C01C00E01C00601C00701C00301C00381C00381C00381C00381C00381C00381C00301C00
+701C00601C00E01C01C01C0380FFFC0015147F9319>I<FFFF801C03801C00801C00801C00401C
+00401C08401C08001C18001FF8001C18001C08001C08201C00201C00201C00601C00401C00C01C
+01C0FFFFC013147F9316>I<00FC200703600C00E0180060300060700020600020E00000E00000
+E00000E00000E00FF8E000E06000E07000E03000E01800E00C00E007036000FC2015147E931A>
+71 D<FFC0001C00001C00001C00001C00001C00001C00001C00001C00001C00001C00001C0000
+1C00401C00401C00401C00C01C00801C01801C0380FFFF8012147F9315>76
+D<FE000FE01E000F00170017001700170017001700138027001380270011C0470011C0470010E0
+870010E0870010E087001071070010710700103A0700103A0700101C0700101C0700381C0700FE
+083FE01B147F931E>I<FC01FC1E007017002017802013802011C02010E0201070201070201038
+20101C20100E20100F201007201003A01001E01000E01000E0380060FE002016147F9319>I<01
+F800070E001C03803801C03000C07000E0600060E00070E00070E00070E00070E00070E0007070
+00E07000E03000C03801C01C0380070E0001F80014147E9319>I<FFFC001C07001C03801C01C0
+1C01C01C01C01C01C01C01C01C03801C07001FFC001C00001C00001C00001C00001C00001C0000
+1C00001C0000FF800012147F9316>I<FFF8001C07001C03801C01C01C01C01C01C01C01C01C03
+801C07001FF8001C0E001C07001C03801C03801C03801C03801C03841C03841C01CCFF80F81614
+7F9318>82 D<7FFFF0607030407010407010807008807008807008007000007000007000007000
+00700000700000700000700000700000700000700000700007FF0015147F9318>84
+D<FF81FC1C00701C00201C00201C00201C00201C00201C00201C00201C00201C00201C00201C00
+201C00201C00200C00200E004006008003830000FC0016147F9319>I<FF1FF0FC380380303803
+80301C03C0201C03C0201E03C0600E04E0400E04E0400704E08007087080070870800388710003
+9039000390390001F03E0001E01E0001E01E0000C00C0000C00C0000C00C001E147F9321>87
+D<FF00FC3C00301E00200E004007004007808003C10001C10001E20000F6000074000038000038
+0000380000380000380000380000380000380001FF0016147F9319>89 D<208041004100820082
+008200C300E380410009097A9311>92 D<7F00E1C0E0404060006007E038606060C060C064C064
+61E43E380E0D7E8C11>97 D<F00030003000300030003000300033E034103808300C3006300630
+0630063006300C3808343023E00F147F9312>I<0FE0187020706020C000C000C000C000C00060
+00201018200FC00C0D7F8C0F>I<00780018001800180018001800180F98187820386018C018C0
+18C018C018C0186018203810580F9E0F147F9312>I<0F80104020206030C010FFF0C000C000C0
+006000201018200FC00C0D7F8C0F>I<03C00CE018E01840180018001800FF0018001800180018
+0018001800180018001800180018007F000B1480930A>I<0F3C30E62040606060606060204030
+C02F00600060003FE03FF06018C00CC00CC00C601830300FC00F147F8C11>I<F0003000300030
+0030003000300033E034303818301830183018301830183018301830183018FC7E0F147F9312>
+I<2070200000000000F03030303030303030303030FC06157F9409>I<02070200000000000F03
+0303030303030303030303030343E2E67C081B82940A>I<F00030003000300030003000300030
+F8306030403080330037003B80318030C0306030703030FC7C0E147F9311>I<F0303030303030
+303030303030303030303030FC06147F9309>I<F3E1F0343218381C0C30180C30180C30180C30
+180C30180C30180C30180C30180C30180CFC7E3F180D7F8C1B>I<F3E034303818301830183018
+301830183018301830183018FC7E0F0D7F8C12>I<0FC0186020106018C00CC00CC00CC00CC00C
+6018601838700FC00E0D7F8C11>I<F3E034303808300C30063006300630063006300C38083430
+33E030003000300030003000FC000F137F8C12>I<0F88184820386018C018C018C018C018C018
+6018203818580F9800180018001800180018007E0F137F8C11>I<F3C034E038E0304030003000
+300030003000300030003000FE000B0D7F8C0D>I<3E806180C080C080E0007E003F8003C080C0
+80C0C0C0E1809F000A0D7F8C0D>I<10001000100030007000FF80300030003000300030003000
+300030803080308011000E0009127F910D>I<F078301830183018301830183018301830183018
+303818580F9E0F0D7F8C12>I<F87C301830101820182018200C400C4006800680078003000300
+0E0D7F8C11>I<F87CF8707030305820305820188840188C40188C400D04800D06800D06800603
+00060300060300150D7F8C18>I<F87C303018600C400C800700030007800CC008E010603030F8
+7C0E0D7F8C11>I<F87C301830101820182018200C400C400680068007800300030002000200E6
+00E400E80070000E137F8C11>I<FFF0C06080C081C08180030006000C101810383030206060FF
+E00C0D7F8C0F>I<FFFFFFFF2001808821>124 D E /Fd 2 94 df<FEFEC0C0C0C0C0C0C0C0C0C0
+C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0FEFE07297C9E0C>91
+D<FEFE060606060606060606060606060606060606060606060606060606060606060606060606
+06FEFE0729809E0C>93 D E /Fe 27 123 df<001F8F000020D9800060990000C0300000C03000
+00C0300000C0300007FFFE000180300001806000018060000180600001806000030060000300C0
+000300C0000300C0000300C0000600C00006018000060180000601800004010000CCC30000C8C6
+000070780000191A819315>11 D<000FF000301800601000600000C00000C00000C00007FFE000
+C0600180600180C00180C00180C00180C00181800301900301900301900301A00300E006000006
+0000060000C40000C80000700000151A819314>I<FEFC07027D860C>45
+D<000080000180000300000300000600000600000C000018000018000030000030000060000060
+0000C0000180000180000300000300000600000C00000C00001800001800003000003000006000
+00C00000C00000800000111D7E9512>47 D<07C03F8000C00C0001600800016008000120080001
+300800023010000218100002181000020C1000040C200004042000040620000402200008034000
+080340000801C0000801C00018008000FE00800019147E9319>78 D<07B00C7010703060606060
+606060C0C0C0C8C0C841C862D03C700D0D7C8C12>97 D<7C000C00180018001800180030003700
+388030C060C060C060C060C0C180C180C1004300660038000A147C9310>I<07800C4010603040
+600060006000C000C0004020404021801E000B0D7C8C10>I<007C000C00180018001800180030
+07B00C7010703060606060606060C0C0C0C8C0C841C862D03C700E147C9312>I<07800C401020
+304060407F8060004000C0004020604021801E000B0D7C8C10>I<001C00660064006000C000C0
+00C007F800C001800180018001800180030003000300030003000200060006000600C400C80070
+000F1A81930B>I<01D8023804380C3018301830183030603060306010E019C00EC000C000C001
+80C180C3007C000D137E8C10>I<3E0006000C000C000C000C00180019E01E3018303830303030
+3030306060606460C460C4C0C8C0700E147D9312>I<02060000000000384C4C8C981818303262
+62643807147D930B>I<7C0C181818183030303060606060C0D0D0D0D06006147C9309>108
+D<30F878590D8C4E0E0C9C0E0C980C0C180C0C180C0C3018183018193018313018316030326030
+1C180D7D8C1C>I<30F05B184C189C189818181818183030303230623062606460380F0D7D8C13>
+I<03800C6018203030603060306030C060C06040C0608023001E000C0D7C8C12>I<0C78168C13
+0426062606060606060C0C0C0C0C080C101A2019C018001800300030003000FC000F137F8C12>
+I<31F05A184C109C009800180018003000300030003000600060000D0D7D8C0F>114
+D<0700188018C0308038001E001F0003800180C180810082007C000A0D7D8C0E>I<04000C000C
+000C001800FF8018001800300030003000300060006100610062006400380009127D910C>I<38
+184C184C188C3098301830183030603064306430E411E80E380E0D7D8C12>I<38104C384C108C
+10981018101810302030203040304018800F000D0D7D8C10>I<071E09E311C221802180018001
+800300030403044308C51078E0100D7F8C10>120 D<38184C184C188C30983018301830306030
+60306030E011C00EC000C000802180630046003C000D137D8C11>I<06100F2010E00040008001
+0002000C00102020203840478083000C0D7E8C0E>I E /Ff 55 123 df<0100030003000F803F
+E073704338C338C338C31073007F003FC00FE003F003384318E318E318E33073603FC00F800300
+030001000D1A7E9612>36 D<07001F8019C039C039C039C039BE3B3E3E701C701C701CE03EE06F
+E0E7C0E3C4E38E63CE7EFC3C380F147F9312>38 D<070007000700E738FFF87FF01FC01FC07FF0
+FFF8E7380700070007000D0E7E9012>42 D<038003800380038003800380FFFEFFFEFFFE038003
+8003800380038003800F0F7F9112>I<60F0F878183030E0C00509798312>I<FFF8FFF8FFF80D03
+7E8B12>I<60F0F0600404798312>I<0018003800380070007000E000E001C001C001C003800380
+070007000E000E001C001C001C003800380070007000E000E000C0000D1A7E9612>I<07C00FE0
+1C703838701C701CE00EE00EE00EE00EE00EE00EE00EE01E701C701C38381C700FE007C00F147F
+9312>I<0F803FC070E0E070E038E038403800380030007000E000C00180030006000C00183830
+387FF87FF80D147E9312>50 D<0FE03FF07838701C201C001C0038007807E007F00038001C000E
+000E400EE00EE01C78383FF00FC00F147F9312>I<E000FFFEFFFEE018E038007000E000C001C0
+0380038007000700070007000E000E000E000E000E0004000F157F9412>55
+D<60F0F06000000000000060F0F060040E798D12>58 D<0038007801F003E00F801F003C00F800
+F000F8003C001F000F8003E001F0007800380D117E9212>60 D<FFFEFFFE7FFE0000000000007F
+FEFFFEFFFE0F097F8E12>I<4000E000F0007C003E000F8007C001E000F8007800F801E007C00F
+803E007C00F000E00040000D137E9312>I<03E007F01E18381C30FC71FE739EE30EE70EE70EE7
+0EE70EE30C739C71F830F038001E0E07FE03F80F147F9312>64 D<03E60FFE1C3E381E700E700E
+600EE000E000E000E000E000E000600E700E700E381C1C380FF003E00F147F9312>67
+D<FFFEFFFE380E380E380E3800380038E038E03FE03FE038E038E03800380E380E380E380EFFFE
+FFFE0F147F9312>69 D<FFFEFFFE380E380E380E3800380038E038E03FE03FE038E038E0380038
+00380038003800FF00FF000F147F9312>I<FFE0FFE00E000E000E000E000E000E000E000E000E
+000E000E000E000E000E000E000E00FFE0FFE00B147D9312>73 D<FC7EFC7E7C7C745C76DC76DC
+76DC76DC76DC76DC77DC739C739C701C701C701C701C701CF83EF83E0F147F9312>77
+D<FEFEFEFE3E383A383B383B383B383B383B383B3839B839B839B839B839B839B838B838F8FEF8
+FEF80F147F9312>I<3FE07FF07070E038E038E038E038E038E038E038E038E038E038E038E038
+E038E03870707FF03FE00D147E9312>I<FFE0FFF8383C381C380E380E380E380E381C383C3FF8
+3FE0380038003800380038003800FE00FE000F147F9312>I<FF80FFE038F03878383838383838
+387838F03FE03FC038E0387038703870387038773877FE3EFE1C10147F9312>82
+D<1F303FF070F0E070E070E070E00070007F003FC00FE000F0003800386038E038E030F070FFE0
+CF800D147E9312>I<7FFEFFFEE38EE38EE38E0380038003800380038003800380038003800380
+0380038003801FF01FF00F147F9312>I<FE3F80FE3F80380E00380E00380E00380E00380E0038
+0E00380E00380E00380E00380E00380E00380E00380E00380E001C1C000E380007F00003E00011
+14809312>I<3F807FC070E0207000700FF03FF07870E070E070E07070F03FFE1F3E0F0E7E8D12>
+97 D<F800F80038003800380038003BE03FF03C38381C380C380E380E380E380E380C381C3C38
+3FF01BC00F147F9312>I<07F01FF8383870106000E000E000E000E0006000703838381FF007E0
+0D0E7E8D12>I<00F800F8003800380038003807B81FF8387870386038E038E038E038E0386038
+707838781FFE0FBE0F147F9312>I<07801FE0387070706038E038FFF8FFF8E000600070383838
+1FF007C00D0E7E8D12>I<007E00FF01C70382038003807FFEFFFE038003800380038003800380
+03800380038003803FF83FF81014809312>I<0F9E1FFF38E7707070707070707038E03FC03F80
+70003FE03FF83FFC701EE00EE00EE00E600C783C1FF00FE010167F8D12>I<F800F80038003800
+3800380039E03FF03E383C3838383838383838383838383838383838FE3EFE3E0F147F9312>I<
+06000F000F000600000000000000FF00FF000700070007000700070007000700070007000700FF
+F0FFF00C157D9412>I<00C001E001E000C00000000000001FE01FE000E000E000E000E000E000
+E000E000E000E000E000E000E000E000E000E040C0E1C0FF807E000B1C7E9412>I<F800F80038
+003800380038003BFC3BFC38F039E03BC03F803F803FC03DE038E038703838FC7EFC7E0F147F93
+12>I<FF00FF000700070007000700070007000700070007000700070007000700070007000700
+FFF8FFF80D147E9312>I<F71C00FFBE0079E70079E70071C70071C70071C70071C70071C70071
+C70071C70071C700F9E780F8E380110E808D12>I<F9E0FFF03E383C3838383838383838383838
+383838383838FE3EFE3E0F0E7F8D12>I<0F803FE038E07070E038E038E038E038E038F0787070
+38E03FE00F800D0E7E8D12>I<FBE0FFF03C38381C380C380E380E380E380E380C381C3C383FF0
+3BC038003800380038003800FE00FE000F157F8D12>I<079C1FFC387C703C601CE01CE01CE01C
+E01C601C703C387C1FFC079C001C001C001C001C001C007F007F10157F8D12>I<FCF8FDFC1F1C
+1E081E001C001C001C001C001C001C001C00FFC0FFC00E0E7E8D12>I<1FF03FF06070C070E000
+7F003FE00FF000786018E018F030FFE0DFC00D0E7E8D12>I<06000E000E000E007FF8FFF80E00
+0E000E000E000E000E000E000E380E380E3807F003C00D127F9112>I<F8F8F8F8383838383838
+38383838383838383838383838781FFE0FBE0F0E7F8D12>I<FC7EFC7E38383C781C701C701C70
+0EE00EE00EE006C007C007C003800F0E7F8D12>I<FEFEFEFE701C701C301838383BB83FF83FF8
+3AB838B81CF01CF01CF00F0E7F8D12>I<7C7C7C7C1CF00EE00FC007C00380078007C00EE01EF0
+1C70FC7EFC7E0F0E7F8D12>I<FC7EFC7E3C381C381C701C700E700E600E6006E006E003C003C0
+03C0038003800380778077007E003C000F157F8D12>I<3FFC7FFC7038707000E001C003800700
+0E001C1C381C701CFFFCFFFC0E0E7F8D12>I E /Fg 35 122 df<00038000000380000007C000
+0007C0000007C000000FE000000FE000001FF000001BF000001BF0000031F8000031F8000061FC
+000060FC0000E0FE0000C07E0000C07E0001803F0001FFFF0003FFFF8003001F8003001F800600
+0FC006000FC00E000FE00C0007E0FFC07FFEFFC07FFE1F1C7E9B24>65 D<FFFFF800FFFFFF000F
+C01F800FC00FC00FC007C00FC007E00FC007E00FC007E00FC007E00FC007E00FC007C00FC00F80
+0FC03F000FFFFE000FC00F800FC007C00FC007E00FC003E00FC003F00FC003F00FC003F00FC003
+F00FC003F00FC007E00FC007E00FC01FC0FFFFFF00FFFFFC001C1C7E9B22>I<001FE02000FFF8
+E003F80FE007C003E00F8001E01F0000E03E0000E03E0000607E0000607C000060FC000000FC00
+0000FC000000FC000000FC000000FC000000FC000000FC0000007C0000607E0000603E0000603E
+0000C01F0000C00F80018007C0030003F80E0000FFFC00001FE0001B1C7D9B22>I<FFFFF800FF
+FFFF000FC01FC00FC007E00FC001F00FC001F80FC000F80FC000FC0FC0007C0FC0007C0FC0007E
+0FC0007E0FC0007E0FC0007E0FC0007E0FC0007E0FC0007E0FC0007E0FC0007C0FC0007C0FC000
+7C0FC000F80FC000F80FC001F00FC007E00FC01FC0FFFFFF00FFFFF8001F1C7E9B25>I<FFFFFF
+00FFFFFF000FC01F000FC007000FC003000FC003800FC003800FC181800FC181800FC181800FC1
+80000FC380000FFF80000FFF80000FC380000FC180000FC180000FC180600FC180600FC000E00F
+C000C00FC000C00FC001C00FC001C00FC003C00FC00F80FFFFFF80FFFFFF801B1C7E9B1F>I<FF
+FFFF00FFFFFF000FC01F000FC007000FC003000FC003800FC003800FC001800FC181800FC18180
+0FC180000FC180000FC380000FFF80000FFF80000FC380000FC180000FC180000FC180000FC180
+000FC000000FC000000FC000000FC000000FC000000FC00000FFFF0000FFFF0000191C7E9B1E>
+I<000FF008007FFE3801FC07F807E001F80F8000781F0000783F0000383E0000387E0000187C00
+0018FC000000FC000000FC000000FC000000FC000000FC000000FC007FFFFC007FFF7C0001F87E
+0001F83E0001F83F0001F81F0001F80F8001F807E001F801FC07F8007FFE78000FF818201C7D9B
+26>I<FFFC3FFFFFFC3FFF0FC003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F0
+0FC003F00FC003F00FC003F00FFFFFF00FFFFFF00FC003F00FC003F00FC003F00FC003F00FC003
+F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F00FC003F0FFFC3FFFFFFC3FFF201C
+7E9B25>I<FFFF00FFFF000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000FC0000F
+C0000FC0000FC0000FC0000FC0000FC0000FC0030FC0030FC0030FC0070FC0070FC0060FC00E0F
+C01E0FC07EFFFFFEFFFFFE181C7E9B1D>76 D<FFE003FFFFE003FF0FF000300FF800300DFC0030
+0CFE00300C7E00300C3F00300C1F80300C1FC0300C0FE0300C07F0300C03F0300C01F8300C01FC
+300C00FE300C007F300C003F300C001FB00C001FF00C000FF00C0007F00C0003F00C0001F00C00
+00F00C0000F0FFC00070FFC00030201C7E9B25>78 D<FFFFF800FFFFFE000FC03F800FC00F800F
+C007C00FC007E00FC007E00FC007E00FC007E00FC007E00FC007C00FC007C00FC00F800FC03F00
+0FFFFC000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000000FC000
+000FC000000FC00000FFFC0000FFFC00001B1C7E9B21>80 D<07F8201FFEE03C07E07801E07000
+E0F000E0F00060F00060F80000FE0000FFE0007FFE003FFF003FFF800FFFC007FFE0007FE00003
+F00001F00000F0C000F0C000F0C000E0E000E0F001C0FC03C0EFFF0083FC00141C7D9B1B>83
+D<7FFFFFE07FFFFFE0781F81E0701F80E0601F8060E01F8070C01F8030C01F8030C01F8030C01F
+8030001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F8000001F800000
+1F8000001F8000001F8000001F8000001F8000001F8000001F800007FFFE0007FFFE001C1C7E9B
+21>I<FFFC03FFFFFC03FF0FC000300FC000300FC000300FC000300FC000300FC000300FC00030
+0FC000300FC000300FC000300FC000300FC000300FC000300FC000300FC000300FC000300FC000
+300FC000300FC0003007C0003007C0006003E000E001F001C000FC0780007FFE00000FF800201C
+7E9B25>I<FFFC7FFE0FFCFFFC7FFE0FFC0FC007E000C00FC007F000C00FE003F001C007E003F0
+018007E007F8018003F007F8030003F007F8030003F80CFC070001F80CFC060001F81CFE060001
+FC187E0E0000FC187E0C0000FC387F0C00007E303F1800007E303F1800007F601FB800003F601F
+B000003FE01FF000003FC00FF000001FC00FE000001FC00FE000000F8007C000000F8007C00000
+0F0003C0000007000380000007000380002E1C7F9B31>87 D<0FF8001C1E003E0F803E07803E07
+C01C07C00007C0007FC007E7C01F07C03C07C07C07C0F807C0F807C0F807C0780BC03E13F80FE1
+F815127F9117>97 D<FF0000FF00001F00001F00001F00001F00001F00001F00001F00001F0000
+1F00001F3F801FE1E01F80701F00781F003C1F003C1F003E1F003E1F003E1F003E1F003E1F003E
+1F003C1F003C1F00781F80701EC1E01C3F00171D7F9C1B>I<03FC000E0E001C1F003C1F00781F
+00780E00F80000F80000F80000F80000F80000F800007800007801803C01801C03000E0E0003F8
+0011127E9115>I<000FF0000FF00001F00001F00001F00001F00001F00001F00001F00001F000
+01F001F9F00F07F01C03F03C01F07801F07801F0F801F0F801F0F801F0F801F0F801F0F801F078
+01F07801F03C01F01C03F00F0FFE03F9FE171D7E9C1B>I<01FC000F07001C03803C01C07801C0
+7801E0F801E0F801E0FFFFE0F80000F80000F800007800007C00603C00601E00C00F038001FC00
+13127F9116>I<03F8F00E0F381E0F381C07303C07803C07803C07803C07801C07001E0F000E0E
+001BF8001000001800001800001FFF001FFFC00FFFE01FFFF07801F8F00078F00078F000787000
+707800F01E03C007FF00151B7F9118>103 D<FF0000FF00001F00001F00001F00001F00001F00
+001F00001F00001F00001F00001F0FC01F31E01F40F01F80F81F80F81F00F81F00F81F00F81F00
+F81F00F81F00F81F00F81F00F81F00F81F00F81F00F8FFE7FFFFE7FF181D7F9C1B>I<1E003F00
+3F003F003F001E00000000000000000000000000FF00FF001F001F001F001F001F001F001F001F
+001F001F001F001F001F001F00FFE0FFE00B1E7F9D0E>I<FF0000FF00001F00001F00001F0000
+1F00001F00001F00001F00001F00001F00001F0FF81F0FF81F03801F07001F0C001F18001F7000
+1FF8001FFC001FBC001F3E001F1F001F0F001F0F801F07C01F03E0FFC7FCFFC7FC161D7F9C19>
+107 D<FF00FF001F001F001F001F001F001F001F001F001F001F001F001F001F001F001F001F00
+1F001F001F001F001F001F001F001F001F00FFE0FFE00B1D7F9C0E>I<FF0FC07E00FF31E18F00
+1F40F207801F80FC07C01F80FC07C01F00F807C01F00F807C01F00F807C01F00F807C01F00F807
+C01F00F807C01F00F807C01F00F807C01F00F807C01F00F807C01F00F807C0FFE7FF3FF8FFE7FF
+3FF825127F9128>I<FF0FC0FF31E01F40F01F80F81F80F81F00F81F00F81F00F81F00F81F00F8
+1F00F81F00F81F00F81F00F81F00F81F00F8FFE7FFFFE7FF18127F911B>I<01FC000F07801C01
+C03C01E07800F07800F0F800F8F800F8F800F8F800F8F800F8F800F87800F07800F03C01E01E03
+C00F078001FC0015127F9118>I<FF3F80FFE1E01F80F01F00781F007C1F003C1F003E1F003E1F
+003E1F003E1F003E1F003E1F003C1F007C1F00781F80F01FC1E01F3F001F00001F00001F00001F
+00001F00001F0000FFE000FFE000171A7F911B>I<FE3E00FE47001E8F801E8F801E8F801F0700
+1F00001F00001F00001F00001F00001F00001F00001F00001F00001F0000FFF000FFF00011127F
+9114>114 D<1FD830786018E018E018F000FF807FE07FF01FF807FC007CC01CC01CE01CE018F8
+30CFC00E127E9113>I<0300030003000300070007000F000F003FFCFFFC1F001F001F001F001F
+001F001F001F001F001F0C1F0C1F0C1F0C0F08079803F00E1A7F9913>I<FF07F8FF07F81F00F8
+1F00F81F00F81F00F81F00F81F00F81F00F81F00F81F00F81F00F81F00F81F00F81F01F80F01F8
+0786FF01F8FF18127F911B>I<FFC7FCFFC7FC1F81800F838007C70003EE0001FC0001F80000F8
+00007C0000FE0001DF00039F00070F800607C00C03E0FF07FCFF07FC16127F9119>120
+D<FFC1FCFFC1FC1F00601F80E00F80C00FC0C007C18007C18003E30003E30001F70001F60000FE
+0000FC0000FC00007800007800003000003000007000706000F86000F8C000F980007300003E00
+00161A7F9119>I E /Fh 47 122 df<020408103020604040C0C0C0C0C0C0C0C0404060203010
+080402071A7F920C>40 D<8040201018080C0404060606060606060604040C081810204080071A
+7E920C>I<40E060202040408003087E8209>44 D<40E04003037E8209>46
+D<0C003C00CC000C000C000C000C000C000C000C000C000C000C000C000C00FF8009107E8F0F>
+49 D<1F00618040C08060C0600060006000C00180030006000C00102020207FC0FFC00B107F8F
+0F>I<1F00218060C060C000C0008001800F00008000400060C060C060804060801F000B107F8F
+0F>I<0300030007000F000B001300330023004300C300FFE003000300030003001FE00B107F8F
+0F>I<1F00318060C0C040C060C060C06040E021E01E600060004060C0608043003E000B107F8F
+0F>57 D<40E040000000000040E060202040408003107E8A09>59 D<03E0000C180010040023C2
+004631004C0D00980C80980C80980C80980C80980C804C0C80463C8023C7001000000C038003FC
+0011117E9017>64 D<FFF8180C18061803180318031806181C1FFC180618031803180318031806
+180EFFF810117F9015>66 D<03F10C0B1807300360014001C000C000C000C000C0004001600130
+0218020C0C03F010117E9016>I<FFF800180C001803001801001801801800801800C01800C018
+00C01800C01800C01800C0180180180100180300180E00FFF80012117F9017>I<FFFE18061802
+180318011821182018601FE01860182018201800180018001800FF0010117F9014>70
+D<03F1000C0B00180700300300600100400100C00000C00000C00000C03FC0C003004003006003
+003003001803000C070003F90012117E9017>I<FF181818181818181818181818181818FF0811
+7F900B>73 D<FF0018001800180018001800180018001800180018021802180218061804181CFF
+FC0F117F9013>76 D<F81FC01C07001C020016020013020013020011820010C20010C200106200
+103200101200101A00100E00100600380600FE020012117F9016>78 D<FFF0181C180418061806
+18061804181C1FF01800180018001800180018001800FF000F117F9014>80
+D<FFE000181800180C00180600180600180600180C001818001FE000181800180C00180C00180C
+00180C00180C20180420FF03C013117F9016>82 D<1F2060E0006080208020800060003E001F80
+00C00060002080208020C040E0C09F000B117E9011>I<7FFF8060C18040C080C0C0C080C04080
+C04000C00000C00000C00000C00000C00000C00000C00000C00000C00000C0000FFC0012117F90
+16>I<FF1FC0180700180200180200180200180200180200180200180200180200180200180200
+1802000802000C040006080001F00012117F9016>I<FC07C03003003003001802001802000C04
+000C040006080006080006080003100003100001A00001A00001E00000C00000C00012117F9016
+>I<3E006300018001800F8031804180C190C19063903DE00C0B7F8A0F>97
+D<F0003000300030003000300037C038603030301830183018301830183030386027800D117F90
+11>I<1F8030C06000C000C000C000C000C000604030801F000A0B7F8A0E>I<01E0006000600060
+006000600F6030E06060C060C060C060C060C060606030E01F780D117F9011>I<1F00318060C0
+C0C0FFC0C000C000C000604030801F000A0B7F8A0E>I<07000D801800180018001800FE001800
+180018001800180018001800180018007E00091180900A>I<1EF0331061806180618033003E00
+400060003F803FC060E0C060C060C06060C01F000C117F8A0F>I<F00030003000300030003000
+33C03C6030603060306030603060306030603060FCF80D117F9011>I<30703000000000F03030
+30303030303030FC0612809108>I<F0003000300030003000300031F030C03080330036003F00
+3300318031C030C0F9F00C117F9010>107 D<F0303030303030303030303030303030FC061180
+9008>I<F3C3C03C2C20383830303030303030303030303030303030303030303030FCFCFC160B
+7F8A1A>I<F3C03C6030603060306030603060306030603060FCF80D0B7F8A11>I<1F00318060C0
+C060C060C060C060C06060C031801F000B0B7F8A0F>I<F7C03860303030183018301830183018
+3030386037803000300030003000FC000D107F8A11>I<F7003980300030003000300030003000
+30003000FC00090B7F8A0C>114 D<3E028280783E038181C2BC080B7F8A0C>I<10103030FE3030
+303030323232321C070F7F8E0C>I<F1E03060306030603060306030603060306030E00F780D0B
+7F8A11>I<F8F0706030403040188018800D000D000D00060006000C0B7F8A10>I<F9F3C060E180
+30E10030E1003131001932001A12000E1C000E1C000C0C00040800120B7F8A16>I<F8F0306030
+403040188018800D000D000F000600060004000400CC00C80070000C107F8A10>121
+D E /Fi 12 86 df<FFFFFF8000FFFFFFE00007F001F80007F000FC0007F0007E0007F0007E00
+07F0007F0007F0007F0007F0007F0007F0007F0007F0007F0007F0007E0007F000FE0007F000FC
+0007F003F80007FFFFF00007FFFFF00007F001FC0007F0007E0007F0003F0007F0003F8007F000
+1F8007F0001FC007F0001FC007F0001FC007F0001FC007F0001FC007F0001FC007F0003F8007F0
+003F8007F0007F0007F001FE00FFFFFFF800FFFFFFC00022227EA128>66
+D<0003FE0080001FFF818000FF01E38001F8003F8003E0001F8007C0000F800F800007801F8000
+07803F000003803F000003807F000001807E000001807E00000180FE00000000FE00000000FE00
+000000FE00000000FE00000000FE00000000FE00000000FE000000007E000000007E000001807F
+000001803F000001803F000003801F800003000F8000030007C000060003F0000C0001F8003800
+00FF00F000001FFFC0000003FE000021227DA128>I<FFFFFF8000FFFFFFF00007F003FC0007F0
+007E0007F0003F0007F0001F8007F0000FC007F00007E007F00007E007F00007F007F00003F007
+F00003F007F00003F007F00003F807F00003F807F00003F807F00003F807F00003F807F00003F8
+07F00003F807F00003F807F00003F807F00003F007F00003F007F00003F007F00007E007F00007
+E007F0000FC007F0001F8007F0003F0007F0007E0007F003FC00FFFFFFF000FFFFFF800025227E
+A12B>I<FFFFFFFCFFFFFFFC07F000FC07F0003C07F0001C07F0000C07F0000E07F0000E07F000
+0607F0180607F0180607F0180607F0180007F0380007F0780007FFF80007FFF80007F0780007F0
+380007F0180007F0180007F0180307F0180307F0000307F0000607F0000607F0000607F0000E07
+F0000E07F0001E07F0003E07F001FCFFFFFFFCFFFFFFFC20227EA125>I<FFFFFFF8FFFFFFF807
+F001F807F0007807F0003807F0001807F0001C07F0001C07F0000C07F0000C07F0180C07F0180C
+07F0180007F0180007F0380007F0780007FFF80007FFF80007F0780007F0380007F0180007F018
+0007F0180007F0180007F0000007F0000007F0000007F0000007F0000007F0000007F0000007F0
+0000FFFFE000FFFFE0001E227EA123>I<0003FE0040001FFFC0C0007F00F1C001F8003FC003F0
+000FC007C00007C00FC00003C01F800003C03F000001C03F000001C07F000000C07E000000C07E
+000000C0FE00000000FE00000000FE00000000FE00000000FE00000000FE00000000FE00000000
+FE000FFFFC7E000FFFFC7F00001FC07F00001FC03F00001FC03F00001FC01F80001FC00FC0001F
+C007E0001FC003F0001FC001FC003FC0007F80E7C0001FFFC3C00003FF00C026227DA12C>I<FF
+FFE0FFFFE003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003
+F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003F80003
+F80003F80003F80003F80003F80003F800FFFFE0FFFFE013227FA115>73
+D<FFFF803FFCFFFF803FFC07F000038007F000070007F0000E0007F000180007F000300007F000
+E00007F001C00007F003800007F007000007F00E000007F018000007F038000007F0FC000007F1
+FE000007F3FE000007F77F000007FE7F800007F83F800007F01FC00007F01FE00007F00FE00007
+F007F00007F007F80007F003F80007F001FC0007F001FE0007F000FF0007F0007F0007F0007F80
+07F0003FC0FFFF83FFFCFFFF83FFFC26227EA12C>75 D<FFF8001FFEFFFC001FFE07FC0000C007
+FE0000C006FF0000C0067F8000C0063FC000C0061FE000C0060FE000C0060FF000C00607F800C0
+0603FC00C00601FE00C00600FE00C00600FF00C006007F80C006003FC0C006001FE0C006000FF0
+C0060007F0C0060007F8C0060003FCC0060001FEC0060000FFC00600007FC00600007FC0060000
+3FC00600001FC00600000FC006000007C006000003C006000003C0FFF00001C0FFF00000C02722
+7EA12C>78 D<0007FC0000003FFF800000FC07E00003F001F80007E000FC000FC0007E001F8000
+3F001F80003F003F00001F803F00001F807F00001FC07E00000FC07E00000FC0FE00000FE0FE00
+000FE0FE00000FE0FE00000FE0FE00000FE0FE00000FE0FE00000FE0FE00000FE0FE00000FE07E
+00000FC07F00001FC07F00001FC03F00001F803F81F03F801F83F83F000FC70C7E0007E606FC00
+03F607F80000FF07E000003FFF80000007FF80200000038020000001C020000001E0E0000001FF
+E0000001FFC0000000FFC0000000FFC00000007F800000007F000000001E00232C7DA12A>81
+D<FFFFFE0000FFFFFFC00007F007F00007F001F80007F000FC0007F0007E0007F0007F0007F000
+7F0007F0007F0007F0007F0007F0007F0007F0007F0007F0007E0007F000FC0007F001F80007F0
+07F00007FFFFC00007FFFF800007F00FE00007F007F00007F003F80007F001FC0007F001FC0007
+F001FC0007F001FC0007F001FC0007F001FC0007F001FC0007F001FC0007F001FC0607F000FE06
+07F000FF0CFFFF803FF8FFFF800FF027227EA12A>I<FFFF803FFCFFFF803FFC07F000018007F0
+00018007F000018007F000018007F000018007F000018007F000018007F000018007F000018007
+F000018007F000018007F000018007F000018007F000018007F000018007F000018007F0000180
+07F000018007F000018007F000018007F000018007F000018007F000018007F000018003F00003
+0003F800030001F800060000FC000E00007E001C00003F80F800000FFFE0000001FF000026227E
+A12B>85 D E end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 300
+TeXDict begin @landscape
+%%EndSetup
+%%Page: 1 1
+bop -225 -183 a Fi(GDB)14 b(QUICK)g(REFERENCE)22 b Fh(GDB)14
+b(V)n(ersion)h(4)-225 -91 y Fg(Essen)o(tial)c(Commands)-225
+-45 y Ff(gdb)i Fe(pr)n(o)n(gr)n(am)f Fd([)p Fe(c)n(or)n(e)p
+Fd(])24 b Fc(debug)14 b Fe(pr)n(o)n(gr)n(am)e Fd([)p Fc(using)i(coredump)g
+Fe(c)n(or)n(e)p Fd(])-225 9 y Ff(b)f Fd([)p Fe(\014le)p Ff(:)p
+Fd(])p Fe(function)68 b Fc(set)13 b(breakp)q(oin)o(t)i(at)e
+Fe(function)g Fd([)p Fc(in)h Fe(\014le)p Fd(])-225 63 y Ff(run)f
+Fd([)p Fe(ar)n(glist)p Fd(])126 b Fc(start)13 b(y)o(our)h(program)f
+Fd([)p Fc(with)h Fe(ar)n(glist)p Fd(])-225 106 y Ff(bt)274
+b Fc(bac)o(ktrace:)20 b(displa)o(y)c(program)d(stac)o(k)-225
+143 y Ff(p)g Fe(expr)214 b Fc(displa)o(y)15 b(the)f(v)n(alue)h(of)e(an)h
+(expression)-225 180 y Ff(c)292 b Fc(con)o(tin)o(ue)14 b(running)h(y)o(our)f
+(program)-225 218 y Ff(n)292 b Fc(next)14 b(line,)h(stepping)g(o)o(v)o(er)f
+(function)g(calls)-225 255 y Ff(s)292 b Fc(next)14 b(line,)h(stepping)g(in)o
+(to)f(function)h(calls)-225 352 y Fg(Starting)c(GDB)-225 398
+y Ff(gdb)256 b Fc(start)13 b(GDB,)h(with)g(no)g(debugging)g(\014les)-225
+435 y Ff(gdb)f Fe(pr)n(o)n(gr)n(am)121 b Fc(b)q(egin)14 b(debugging)g
+Fe(pr)n(o)n(gr)n(am)-225 472 y Ff(gdb)f Fe(pr)n(o)n(gr)n(am)f(c)n(or)n(e)48
+b Fc(debug)14 b(coredump)g Fe(c)n(or)n(e)f Fc(pro)q(duced)h(b)o(y)105
+510 y Fe(pr)n(o)n(gr)n(am)-225 548 y Ff(gdb)f(--help)135 b
+Fc(describ)q(e)14 b(command)g(line)g(options)-225 647 y Fg(Stopping)c(GDB)
+-225 692 y Ff(quit)238 b Fc(exit)14 b(GDB;)g(also)g Ff(q)f
+Fc(or)g Ff(EOF)g Fc(\(eg)g Ff(C-d)p Fc(\))-225 734 y Ff(INTERRUPT)148
+b Fc(\(eg)13 b Ff(C-c)p Fc(\))g(terminate)g(curren)o(t)h(command,)h(or)105
+771 y(send)g(to)e(running)i(pro)q(cess)-225 868 y Fg(Getting)c(Help)-225
+914 y Ff(help)238 b Fc(list)14 b(classes)g(of)g(commands)-225
+951 y Ff(help)e Fe(class)155 b Fc(one-line)14 b(descriptions)h(for)f
+(commands)g(in)105 988 y Fe(class)-225 1021 y Ff(help)e Fe(c)n(ommand)83
+b Fc(describ)q(e)14 b Fe(c)n(ommand)-225 1119 y Fg(Executing)e(y)o(our)h
+(Program)-225 1165 y Ff(run)g Fe(ar)n(glist)150 b Fc(start)13
+b(y)o(our)h(program)f(with)i Fe(ar)n(glist)-225 1203 y Ff(run)256
+b Fc(start)13 b(y)o(our)h(program)f(with)i(curren)o(t)f(argumen)o(t)105
+1240 y(list)-225 1273 y Ff(run)f Fb(:)7 b(:)g(:)12 b Ff(<)p
+Fe(inf)h Ff(>)p Fe(outf)32 b Fc(start)13 b(y)o(our)h(program)f(with)i(input,)
+g(output)105 1310 y(redirected)-225 1360 y Ff(kill)238 b Fc(kill)15
+b(running)g(program)-225 1434 y Ff(tty)e Fe(dev)193 b Fc(use)14
+b Fe(dev)f Fc(as)g(stdin)i(and)f(stdout)g(for)g(next)g Ff(run)-225
+1472 y(set)f(args)f Fe(ar)n(glist)66 b Fc(sp)q(ecify)15 b Fe(ar)n(glist)d
+Fc(for)i(next)g Ff(run)-225 1509 y(set)f(args)171 b Fc(sp)q(ecify)15
+b(empt)o(y)f(argumen)o(t)g(list)-225 1546 y Ff(show)e(args)154
+b Fc(displa)o(y)15 b(argumen)o(t)f(list)-225 1621 y Ff(show)e(environment)28
+b Fc(sho)o(w)13 b(all)i(en)o(vironmen)o(t)g(v)n(ariables)-225
+1659 y Ff(show)d(env)h Fe(var)110 b Fc(sho)o(w)13 b(v)n(alue)i(of)f(en)o
+(vironmen)o(t)h(v)n(ariable)f Fe(var)-225 1696 y Ff(set)f(env)g
+Fe(var)f(string)28 b Fc(set)13 b(en)o(vironmen)o(t)j(v)n(ariable)e
+Fe(var)-225 1733 y Ff(unset)e(env)h Fe(var)92 b Fc(remo)o(v)o(e)13
+b Fe(var)g Fc(from)h(en)o(vironmen)o(t)-225 1820 y Fg(Shell)d(Commands)-225
+1866 y Ff(cd)i Fe(dir)217 b Fc(c)o(hange)13 b(w)o(orking)h(directory)g(to)f
+Fe(dir)-225 1903 y Ff(pwd)256 b Fc(Prin)o(t)15 b(w)o(orking)e(directory)-225
+1941 y Ff(make)f Fb(:)7 b(:)g(:)176 b Fc(call)14 b(\\)p Ff(make)p
+Fc(")-225 1978 y Ff(shell)e Fe(cmd)146 b Fc(execute)13 b(arbitrary)h(shell)h
+(command)f(string)-225 2100 y Fd([)f(])h Fh(surround)f(optional)j(argumen)o
+(ts)45 b Fb(:)7 b(:)g(:)13 b Fh(sho)o(w)h(one)f(or)h(more)f(argumen)o(ts)-216
+2174 y(c)-230 2175 y Fa(\015)p Fh(1991,)h(1992)h(F)n(ree)d(Soft)o(w)o(are)h
+(F)n(oundation,)h(Inc.)60 b(P)o(ermissions)15 b(on)f(bac)o(k)p
+800 -217 1 9 v 800 2175 V 875 -183 a Fg(Breakp)q(oin)o(ts)d(and)j(W)l(atc)o
+(hp)q(oin)o(ts)875 -132 y Ff(break)e Fd([)p Fe(\014le)p Ff(:)p
+Fd(])p Fe(line)875 -86 y Ff(b)i Fd([)p Fe(\014le)p Ff(:)p Fd(])p
+Fe(line)1185 -132 y Fc(set)g(breakp)q(oin)o(t)g(at)f Fe(line)h
+Fc(n)o(um)o(b)q(er)h Fd([)p Fc(in)f Fe(\014le)p Fd(])1185 -94
+y Fc(eg:)33 b Ff(break)12 b(main.c:37)875 -32 y(break)g Fd([)p
+Fe(\014le)p Ff(:)p Fd(])p Fe(func)57 b Fc(set)14 b(breakp)q(oin)o(t)g(at)f
+Fe(func)h Fd([)p Fc(in)g Fe(\014le)p Fd(])875 11 y Ff(break)e(+)p
+Fe(o\013set)875 48 y Ff(break)g(-)p Fe(o\013set)1185 11 y Fc(set)i(break)f
+(at)h Fe(o\013set)f Fc(lines)i(from)f(curren)o(t)g(stop)875
+87 y Ff(break)e(*)p Fe(addr)121 b Fc(set)14 b(breakp)q(oin)o(t)g(at)f
+(address)h Fe(addr)875 124 y Ff(break)220 b Fc(set)14 b(breakp)q(oin)o(t)g
+(at)f(next)i(instruction)875 161 y Ff(break)d Fb(:)7 b(:)g(:)12
+b Ff(if)i Fe(expr)31 b Fc(break)14 b(conditionally)h(on)f(nonzero)f
+Fe(expr)875 211 y Ff(cond)g Fe(n)h Fd([)p Fe(expr)p Fd(])103
+b Fc(new)13 b(conditional)i(expression)g(on)e(breakp)q(oin)o(t)1206
+248 y Fe(n)p Fc(;)h(mak)o(e)g(unconditional)h(if)g(no)e Fe(expr)875
+286 y Ff(tbreak)f Fb(:)7 b(:)g(:)140 b Fc(temp)q(orary)13 b(break;)i(disable)
+f(when)g(reac)o(hed)875 324 y Ff(rbreak)e Fe(r)n(e)n(gex)115
+b Fc(break)14 b(on)f(all)i(functions)g(matc)o(hing)f Fe(r)n(e)n(gex)875
+361 y Ff(watch)e Fe(expr)143 b Fc(set)14 b(a)f(w)o(atc)o(hp)q(oin)o(t)h(for)f
+(expression)i Fe(expr)875 398 y Ff(catch)d Fe(x)192 b Fc(break)14
+b(at)f(C++)i(handler)f(for)g(exception)g Fe(x)875 473 y Ff(info)f(break)135
+b Fc(sho)o(w)13 b(de\014ned)i(breakp)q(oin)o(ts)875 511 y Ff(info)e(watch)135
+b Fc(sho)o(w)13 b(de\014ned)i(w)o(atc)o(hp)q(oin)o(ts)875 585
+y Ff(clear)220 b Fc(delete)14 b(breakp)q(oin)o(ts)g(at)g(next)g(instruction)
+875 635 y Ff(clear)e Fd([)p Fe(\014le)p Ff(:)p Fd(])p Fe(fun)73
+b Fc(delete)14 b(breakp)q(oin)o(ts)g(at)g(en)o(try)g(to)f Fe(fun)p
+Fc(\(\))875 688 y Ff(clear)f Fd([)p Fe(\014le)p Ff(:)p Fd(])p
+Fe(line)66 b Fc(delete)14 b(breakp)q(oin)o(ts)g(on)g(source)f(line)875
+742 y Ff(delete)f Fd([)p Fe(n)p Fd(])147 b Fc(delete)14 b(breakp)q(oin)o(ts)g
+Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])875 823 y Ff(disable)c
+Fd([)p Fe(n)p Fd(])130 b Fc(disable)15 b(breakp)q(oin)o(ts)f
+Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])875 877 y Ff(enable)d
+Fd([)p Fe(n)p Fd(])147 b Fc(enable)14 b(breakp)q(oin)o(ts)g
+Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])875 931 y Ff(enable)d(once)g
+Fd([)p Fe(n)p Fd(])63 b Fc(enable)14 b(breakp)q(oin)o(ts)g
+Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])p Fc(;)1206 969
+y(disable)f(again)g(when)f(reac)o(hed)875 1018 y Ff(enable)f(del)h
+Fd([)p Fe(n)p Fd(])80 b Fc(enable)14 b(breakp)q(oin)o(ts)g
+Fd([)p Fc(or)f(breakp)q(oin)o(t)i Fe(n)p Fd(])p Fc(;)1206 1055
+y(delete)e(when)h(reac)o(hed)875 1105 y Ff(ignore)e Fe(n)i(c)n(ount)76
+b Fc(ignore)13 b(breakp)q(oin)o(t)i Fe(n)p Fc(,)f Fe(c)n(ount)g
+Fc(times)875 1180 y Ff(commands)d Fe(n)946 1217 y Fd([)p Ff(silent)p
+Fd(])946 1255 y Fe(c)n(ommand-list)1185 1180 y Fc(execute)i(GDB)h
+Fe(c)n(ommand-list)e Fc(ev)o(ery)j(time)1206 1217 y(breakp)q(oin)o(t)f
+Fe(n)g Fc(is)g(reac)o(hed.)21 b Fd([)p Ff(silent)1206 1263
+y Fc(suppresses)14 b(default)h(displa)o(y)p Fd(])875 1306 y
+Ff(end)256 b Fc(end)14 b(of)g Fe(c)n(ommand-list)875 1393 y
+Fg(Program)f(Stac)o(k)875 1445 y Ff(backtrace)e Fd([)p Fe(n)p
+Fd(])875 1490 y Ff(bt)i Fd([)p Fe(n)p Fd(])1185 1445 y Fc(prin)o(t)i(trace)e
+(of)g(all)h(frames)g(in)h(stac)o(k;)f(or)f(of)h Fe(n)1206 1482
+y Fc(frames|innermost)g(if)h Fe(n)p Ff(>0)p Fc(,)e(outermost)h(if)1206
+1519 y Fe(n)p Ff(<0)875 1563 y(frame)e Fd([)p Fe(n)p Fd(])165
+b Fc(select)13 b(frame)h(n)o(um)o(b)q(er)h Fe(n)f Fc(or)f(frame)h(at)g
+(address)1206 1600 y Fe(n)p Fc(;)g(if)h(no)e Fe(n)p Fc(,)i(displa)o(y)g
+(curren)o(t)f(frame)875 1639 y Ff(up)f Fe(n)242 b Fc(select)13
+b(frame)h Fe(n)g Fc(frames)g(up)875 1676 y Ff(down)f Fe(n)206
+b Fc(select)13 b(frame)h Fe(n)g Fc(frames)g(do)o(wn)875 1720
+y Ff(info)f(frame)f Fd([)p Fe(addr)p Fd(])30 b Fc(describ)q(e)14
+b(selected)g(frame,)g(or)f(frame)h(at)f Fe(addr)875 1763 y
+Ff(info)g(args)153 b Fc(argumen)o(ts)14 b(of)f(selected)h(frame)875
+1800 y Ff(info)f(locals)117 b Fc(lo)q(cal)13 b(v)n(ariables)i(of)e(selected)h
+(frame)875 1844 y Ff(info)f(reg)f Fd([)p Fe(rn)p Fd(])p Fb(:)7
+b(:)g(:)875 1889 y Ff(info)13 b(all-reg)e Fd([)p Fe(rn)p Fd(])1185
+1844 y Fc(register)i(v)n(alues)i Fd([)p Fc(for)e(regs)g Fe(rn)s
+Fd(])g Fc(in)h(selected)1206 1881 y(frame;)g Ff(all-reg)d Fc(includes)k
+(\015oating)e(p)q(oin)o(t)875 1933 y Ff(info)g(catch)135 b
+Fc(exception)14 b(handlers)h(activ)o(e)e(in)i(selected)f(frame)p
+1900 -217 V 1900 2175 V 1975 -183 a Fg(Execution)f(Con)o(trol)1975
+-138 y Ff(continue)e Fd([)p Fe(c)n(ount)p Fd(])1975 -92 y Ff(c)j
+Fd([)p Fe(c)n(ount)p Fd(])2285 -138 y Fc(con)o(tin)o(ue)g(running;)i(if)e
+Fe(c)n(ount)g Fc(sp)q(eci\014ed,)g(ignore)2306 -100 y(this)g(breakp)q(oin)o
+(t)h(next)f Fe(c)n(ount)g Fc(times)1975 -26 y Ff(step)f Fd([)p
+Fe(c)n(ount)p Fd(])1975 20 y Ff(s)h Fd([)p Fe(c)n(ount)p Fd(])2285
+-26 y Fc(execute)g(un)o(til)h(another)e(line)i(reac)o(hed;)f(rep)q(eat)2306
+12 y Fe(c)n(ount)f Fc(times)i(if)f(sp)q(eci\014ed)1975 74 y
+Ff(stepi)e Fd([)p Fe(c)n(ount)p Fd(])1975 120 y Ff(si)h Fd([)p
+Fe(c)n(ount)p Fd(])2285 74 y Fc(step)h(b)o(y)h(mac)o(hine)f(instructions)h
+(rather)f(than)2306 111 y(source)f(lines)1975 186 y Ff(next)g
+Fd([)p Fe(c)n(ount)p Fd(])1975 232 y Ff(n)h Fd([)p Fe(c)n(ount)p
+Fd(])2285 186 y Fc(execute)g(next)g(line,)h(including)h(an)o(y)e(function)
+2306 223 y(calls)1975 286 y Ff(nexti)e Fd([)p Fe(c)n(ount)p
+Fd(])1975 331 y Ff(ni)h Fd([)p Fe(c)n(ount)p Fd(])2285 286
+y Fc(next)h(mac)o(hine)h(instruction)g(rather)e(than)2306 323
+y(source)g(line)1975 398 y Ff(until)f Fd([)p Fe(lo)n(c)n(ation)p
+Fd(])67 b Fc(run)14 b(un)o(til)i(next)e(instruction)h(\(or)e
+Fe(lo)n(c)n(ation)p Fc(\))1975 441 y Ff(finish)202 b Fc(run)14
+b(un)o(til)i(selected)e(stac)o(k)f(frame)h(returns)1975 484
+y Ff(return)e Fd([)p Fe(expr)p Fd(])101 b Fc(p)q(op)14 b(selected)g(stac)o(k)
+f(frame)h(without)2306 522 y(executing)g Fd([)p Fc(setting)f(return)i(v)n
+(alue)p Fd(])1975 566 y Ff(signal)d Fe(num)125 b Fc(resume)14
+b(execution)g(with)g(signal)h Fe(s)f Fc(\(none)f(if)i Ff(0)p
+Fc(\))1975 604 y Ff(jump)e Fe(line)1975 641 y Ff(jump)g(*)p
+Fe(addr)n(ess)2285 604 y Fc(resume)h(execution)g(at)g(sp)q(eci\014ed)g
+Fe(line)f Fc(n)o(um)o(b)q(er)2306 641 y(or)g Fe(addr)n(ess)1975
+681 y Ff(set)g(var=)p Fe(expr)106 b Fc(ev)n(aluate)14 b Fe(expr)e
+Fc(without)i(displa)o(ying)i(it;)f(use)2306 718 y(for)e(altering)h(program)f
+(v)n(ariables)1975 815 y Fg(Displa)o(y)1975 867 y Ff(print)f
+Fd([)p Ff(/)p Fe(f)6 b Fd(])13 b([)p Fe(expr)p Fd(])1975 913
+y Ff(p)h Fd([)p Ff(/)p Fe(f)5 b Fd(])13 b([)p Fe(expr)p Fd(])2285
+867 y Fc(sho)o(w)h(v)n(alue)g(of)g Fe(expr)e Fd([)p Fc(or)h(last)h(v)n(alue)h
+Ff($)p Fd(])2306 904 y Fc(according)e(to)g(format)h Fe(f)p
+Fc(:)2046 956 y Ff(x)221 b Fc(hexadecimal)2046 993 y Ff(d)g
+Fc(signed)14 b(decimal)2046 1030 y Ff(u)221 b Fc(unsigned)15
+b(decimal)2046 1068 y Ff(o)221 b Fc(o)q(ctal)2046 1105 y Ff(t)g
+Fc(binary)2046 1142 y Ff(a)g Fc(address,)14 b(absolute)g(and)g(relativ)o(e)
+2046 1180 y Ff(c)221 b Fc(c)o(haracter)2046 1217 y Ff(f)g Fc(\015oating)13
+b(p)q(oin)o(t)1975 1266 y Ff(call)g Fd([)p Ff(/)p Fe(f)5 b
+Fd(])13 b Fe(expr)89 b Fc(lik)o(e)15 b Ff(print)d Fc(but)i(do)q(es)g(not)g
+(displa)o(y)h Ff(void)1975 1320 y(x)f Fd([)p Ff(/)p Fe(Nuf)5
+b Fd(])14 b Fe(expr)98 b Fc(examine)14 b(memory)g(at)g(address)g
+Fe(expr)p Fc(;)f(optional)2306 1358 y(format)g(sp)q(ec)h(follo)o(ws)g(slash)
+2011 1396 y Fe(N)249 b Fc(coun)o(t)14 b(of)f(ho)o(w)h(man)o(y)h(units)g(to)e
+(displa)o(y)2011 1433 y Fe(u)256 b Fc(unit)15 b(size;)f(one)g(of)2356
+1471 y Ff(b)f Fc(individual)k(b)o(ytes)2356 1508 y Ff(h)c Fc(halfw)o(ords)h
+(\(t)o(w)o(o)f(b)o(ytes\))2356 1545 y Ff(w)g Fc(w)o(ords)h(\(four)g(b)o
+(ytes\))2356 1583 y Ff(g)f Fc(gian)o(t)h(w)o(ords)f(\(eigh)o(t)h(b)o(ytes\))
+2011 1620 y Fe(f)263 b Fc(prin)o(ting)15 b(format.)21 b(An)o(y)14
+b Ff(print)e Fc(format,)i(or)2356 1657 y Ff(s)f Fc(n)o(ull-terminated)j
+(string)2356 1695 y Ff(i)d Fc(mac)o(hine)h(instructions)1975
+1738 y Ff(disassem)d Fd([)p Fe(addr)p Fd(])62 b Fc(displa)o(y)15
+b(memory)g(as)e(mac)o(hine)h(instructions)1975 1840 y Fg(Automatic)e(Displa)o
+(y)1975 1891 y Ff(display)g Fd([)p Ff(/)p Fe(f)5 b Fd(])13
+b Fe(expr)36 b Fc(sho)o(w)14 b(v)n(alue)g(of)g Fe(expr)e Fc(eac)o(h)i(time)g
+(program)2306 1929 y(stops)g Fd([)p Fc(according)e(to)i(format)f
+Fe(f)6 b Fd(])1975 1972 y Ff(display)184 b Fc(displa)o(y)15
+b(all)g(enabled)f(expressions)h(on)f(list)1975 2014 y Ff(undisplay)d
+Fe(n)118 b Fc(remo)o(v)o(e)14 b(n)o(um)o(b)q(er\(s\))h Fe(n)f
+Fc(from)g(list)h(of)2306 2051 y(automatically)f(displa)o(y)o(ed)h
+(expressions)1975 2091 y Ff(disable)d(disp)g Fe(n)69 b Fc(disable)15
+b(displa)o(y)g(for)f(expression\(s\))h(n)o(um)o(b)q(er)g Fe(n)1975
+2132 y Ff(enable)d(disp)g Fe(n)87 b Fc(enable)14 b(displa)o(y)h(for)f
+(expression\(s\))h(n)o(um)o(b)q(er)g Fe(n)1975 2170 y Ff(info)e(display)99
+b Fc(n)o(um)o(b)q(ered)15 b(list)g(of)e(displa)o(y)j(expressions)p
+eop
+%%Page: 2 2
+bop -225 -183 a Fg(Expressions)-225 -138 y Fe(expr)245 b Fc(an)13
+b(expression)i(in)g(C,)f(C++,)g(or)g(Mo)q(dula-2)105 -100 y(\(including)i
+(function)f(calls\),)f(or:)-225 -60 y Fe(addr)s Ff(@)p Fe(len)176
+b Fc(an)13 b(arra)o(y)h(of)f Fe(len)h Fc(elemen)o(ts)h(b)q(eginning)f(at)105
+-23 y Fe(addr)-225 10 y(\014le)p Ff(::)p Fe(nm)182 b Fc(a)13
+b(v)n(ariable)h(or)g(function)h Fe(nm)e Fc(de\014ned)i(in)f
+Fe(\014le)-225 59 y Fa(f)p Fe(typ)n(e)p Fa(g)p Fe(addr)138
+b Fc(read)13 b(memory)h(at)g Fe(addr)e Fc(as)h(sp)q(eci\014ed)h
+Fe(typ)n(e)-225 105 y Ff($)292 b Fc(most)13 b(recen)o(t)h(displa)o(y)o(ed)i
+(v)n(alue)-225 142 y Ff($)p Fe(n)273 b(n)p Fc(th)14 b(displa)o(y)o(ed)i(v)n
+(alue)-225 179 y Ff($$)274 b Fc(displa)o(y)o(ed)15 b(v)n(alue)g(previous)g
+(to)e($)-225 217 y Ff($$)p Fe(n)255 b(n)p Fc(th)14 b(displa)o(y)o(ed)i(v)n
+(alue)e(bac)o(k)g(from)g($)-225 254 y Ff($)p -205 254 11 2
+v 292 w Fc(last)g(address)g(examined)g(with)h Ff(x)-225 291
+y($)p -205 291 V -193 291 V 292 w Fc(v)n(alue)f(at)g(address)g($)p
+357 291 10 2 v -225 329 a Ff($)p Fe(var)243 b Fc(con)o(v)o(enience)14
+b(v)n(ariable;)h(assign)f(an)o(y)g(v)n(alue)-225 410 y Ff(show)e(values)g
+Fd([)p Fe(n)p Fd(])63 b Fc(sho)o(w)13 b(last)h(10)f(v)n(alues)i
+Fd([)p Fc(or)e(surrounding)i($)p Fe(n)p Fd(])-225 453 y Ff(show)d
+(convenience)28 b Fc(displa)o(y)15 b(all)f(con)o(v)o(enience)h(v)n(ariables)
+-225 550 y Fg(Sym)o(b)q(ol)d(T)l(able)-225 595 y Ff(info)g(address)g
+Fe(s)74 b Fc(sho)o(w)13 b(where)h(sym)o(b)q(ol)h Fe(s)f Fc(is)g(stored)-225
+645 y Ff(info)e(func)h Fd([)p Fe(r)n(e)n(gex)p Fd(])42 b Fc(sho)o(w)13
+b(names,)i(t)o(yp)q(es)f(of)g(de\014ned)g(functions)105 682
+y(\(all,)h(or)e(matc)o(hing)h Fe(r)n(e)n(gex)p Fc(\))-225 733
+y Ff(info)e(var)h Fd([)p Fe(r)n(e)n(gex)p Fd(])60 b Fc(sho)o(w)13
+b(names,)i(t)o(yp)q(es)f(of)g(global)f(v)n(ariables)i(\(all,)105
+770 y(or)f(matc)o(hing)g Fe(r)n(e)n(gex)p Fc(\))-225 821 y
+Ff(whatis)e Fd([)p Fe(expr)p Fd(])-225 867 y Ff(ptype)g Fd([)p
+Fe(expr)p Fd(])85 821 y Fc(sho)o(w)h(data)h(t)o(yp)q(e)g(of)g
+Fe(expr)e Fd([)p Fc(or)h Ff($)p Fd(])g Fc(without)105 858 y(ev)n(aluating;)i
+Ff(ptype)d Fc(giv)o(es)i(more)g(detail)-225 910 y Ff(ptype)e
+Fe(typ)n(e)147 b Fc(describ)q(e)14 b(t)o(yp)q(e,)h(struct,)f(union,)h(or)f
+(en)o(um)-225 1008 y Fg(GDB)f(Scripts)-225 1054 y Ff(source)f
+Fe(script)104 b Fc(read,)14 b(execute)f(GDB)h(commands)g(from)g(\014le)105
+1091 y Fe(script)-225 1147 y Ff(define)e Fe(cmd)-154 1184 y(c)n(ommand-list)
+85 1147 y Fc(create)g(new)i(GDB)g(command)g Fe(cmd)p Fc(;)f(execute)105
+1184 y(script)i(de\014ned)f(b)o(y)h Fe(c)n(ommand-list)-225
+1222 y Ff(end)256 b Fc(end)14 b(of)g Fe(c)n(ommand-list)-225
+1260 y Ff(document)d Fe(cmd)-154 1297 y(help-text)85 1260 y
+Fc(create)h(online)j(do)q(cumen)o(tation)f(for)f(new)h(GDB)105
+1297 y(command)g Fe(cmd)-225 1335 y Ff(end)256 b Fc(end)14
+b(of)g Fe(help-text)-225 1432 y Fg(Signals)-225 1478 y Ff(handle)e
+Fe(signal)h(act)44 b Fc(sp)q(ecify)15 b(GDB)e(actions)h(for)f
+Fe(signal)p Fc(:)-190 1515 y Ff(print)185 b Fc(announce)13
+b(signal)-190 1553 y Ff(noprint)149 b Fc(b)q(e)13 b(silen)o(t)i(for)f(signal)
+-190 1590 y Ff(stop)203 b Fc(halt)14 b(execution)g(on)g(signal)-190
+1627 y Ff(nostop)167 b Fc(do)13 b(not)h(halt)g(execution)-190
+1665 y Ff(pass)203 b Fc(allo)o(w)13 b(y)o(our)h(program)f(to)h(handle)g
+(signal)-190 1702 y Ff(nopass)167 b Fc(do)13 b(not)h(allo)o(w)g(y)o(our)g
+(program)f(to)g(see)h(signal)-225 1739 y Ff(info)e(signals)100
+b Fc(sho)o(w)13 b(table)h(of)g(signals,)h(GDB)e(action)h(for)f(eac)o(h)-225
+1838 y Fg(Debugging)e(T)l(argets)-225 1884 y Ff(target)h Fe(typ)n(e)g(p)n(ar)
+n(am)24 b Fc(connect)13 b(to)g(target)g(mac)o(hine,)i(pro)q(cess,)e(or)h
+(\014le)-225 1921 y Ff(help)e(target)118 b Fc(displa)o(y)15
+b(a)o(v)n(ailable)g(targets)-225 1958 y Ff(attach)d Fe(p)n(ar)n(am)97
+b Fc(connect)13 b(to)g(another)h(pro)q(cess)-225 1996 y Ff(detach)202
+b Fc(release)13 b(target)f(from)i(GDB)g(con)o(trol)p 800 -217
+1 9 v 800 2175 V 875 -183 a Fg(Con)o(trollin)o(g)d(GDB)875
+-138 y Ff(set)i Fe(p)n(ar)n(am)f(value)61 b Fc(set)14 b(one)f(of)h(GDB's)g
+(in)o(ternal)h(parameters)875 -100 y Ff(show)e Fe(p)n(ar)n(am)132
+b Fc(displa)o(y)15 b(curren)o(t)f(setting)g(of)g(parameter)875
+-51 y(P)o(arameters)f(understo)q(o)q(d)h(b)o(y)h Ff(set)e Fc(and)h
+Ff(show)p Fc(:)910 -13 y Ff(complaints)d Fe(limit)i Fc(n)o(um)o(b)q(er)i(of)e
+(messages)h(on)f(un)o(usual)j(sym)o(b)q(ols)910 28 y Ff(confirm)c
+Fe(on/o\013)43 b Fc(enable)14 b(or)f(disable)i(cautionary)f(queries)910
+66 y Ff(editing)e Fe(on/o\013)43 b Fc(con)o(trol)13 b Ff(readline)e
+Fc(command-line)k(editing)910 103 y Ff(height)d Fe(lpp)110
+b Fc(n)o(um)o(b)q(er)15 b(of)e(lines)i(b)q(efore)f(pause)g(in)g(displa)o(y)
+910 145 y Ff(language)d Fe(lang)58 b Fc(Language)12 b(for)h(GDB)h
+(expressions)h(\()p Ff(auto)p Fc(,)e Ff(c)g Fc(or)1206 182
+y Ff(modula-2)p Fc(\))910 222 y Ff(listsize)e Fe(n)101 b Fc(n)o(um)o(b)q(er)
+15 b(of)e(lines)i(sho)o(wn)f(b)o(y)h Ff(list)910 259 y(prompt)d
+Fe(str)114 b Fc(use)14 b Fe(str)f Fc(as)g(GDB)h(prompt)910
+297 y Ff(radix)e Fe(b)n(ase)111 b Fc(o)q(ctal,)13 b(decimal,)i(or)e(hex)i(n)o
+(um)o(b)q(er)1206 334 y(represen)o(tation)910 374 y Ff(verbose)d
+Fe(on/o\013)43 b Fc(con)o(trol)13 b(messages)g(when)h(loading)g(sym)o(b)q
+(ols)910 411 y Ff(width)e Fe(cpl)130 b Fc(n)o(um)o(b)q(er)15
+b(of)e(c)o(haracters)g(b)q(efore)h(line)g(folded)910 449 y
+Ff(write)e Fe(on/o\013)79 b Fc(Allo)o(w)13 b(or)h(forbid)g(patc)o(hing)h
+(binary)m(,)g(core)e(\014les)1206 486 y(\(when)g(reop)q(ened)h(with)g
+Ff(exec)f Fc(or)g Ff(core)p Fc(\))910 526 y Ff(history)f Fb(:)7
+b(:)g(:)910 563 y Ff(h)14 b Fb(:)7 b(:)g(:)1185 526 y Fc(groups)14
+b(with)g(the)g(follo)o(wing)g(options:)910 598 y Ff(h)g(exp)f
+Fe(o\013/on)82 b Fc(disable/enable)14 b Ff(readline)d Fc(history)k(expansion)
+910 635 y Ff(h)f(file)e Fe(\014lename)33 b Fc(\014le)14 b(for)f(recording)h
+(GDB)f(command)h(history)910 672 y Ff(h)g(size)e Fe(size)104
+b Fc(n)o(um)o(b)q(er)15 b(of)e(commands)h(k)o(ept)h(in)f(history)h(list)910
+710 y Ff(h)f(save)e Fe(o\013/on)65 b Fc(con)o(trol)13 b(use)h(of)g(external)g
+(\014le)g(for)f(command)1206 747 y(history)910 803 y Ff(print)f
+Fb(:)7 b(:)g(:)910 840 y Ff(p)14 b Fb(:)7 b(:)g(:)1185 803
+y Fc(groups)14 b(with)g(the)g(follo)o(wing)g(options:)910 882
+y Ff(p)g(address)d Fe(on/o\013)h Fc(prin)o(t)j(memory)f(addresses)g(in)g
+(stac)o(ks,)h(v)n(alues)910 923 y Ff(p)f(array)e Fe(o\013/on)47
+b Fc(compact)13 b(or)g(attractiv)o(e)g(format)h(for)g(arra)o(ys)910
+965 y Ff(p)g(demangl)d Fe(on/o\013)h Fc(source)h(\(demangled\))h(or)g(in)o
+(ternal)g(form)g(for)1206 1002 y(C++)g(sym)o(b)q(ols)910 1042
+y Ff(p)g(asm-dem)d Fe(on/o\013)h Fc(demangle)i(C++)g(sym)o(b)q(ols)h(in)g
+(mac)o(hine-)1206 1079 y(instruction)g(output)910 1118 y Ff(p)f(elements)d
+Fe(limit)17 b Fc(n)o(um)o(b)q(er)e(of)e(arra)o(y)h(elemen)o(ts)g(to)g(displa)
+o(y)910 1160 y Ff(p)g(object)e Fe(on/o\013)29 b Fc(prin)o(t)15
+b(C++)f(deriv)o(ed)h(t)o(yp)q(es)g(for)e(ob)r(jects)910 1201
+y Ff(p)h(pretty)e Fe(o\013/on)29 b Fc(struct)14 b(displa)o(y:)23
+b(compact)13 b(or)g(inden)o(ted)910 1243 y Ff(p)h(union)e Fe(on/o\013)47
+b Fc(displa)o(y)15 b(of)f(union)h(mem)o(b)q(ers)910 1284 y
+Ff(p)f(vtbl)e Fe(o\013/on)65 b Fc(displa)o(y)15 b(of)f(C++)h(virtual)f
+(function)h(tables)875 1359 y Ff(show)e(commands)81 b Fc(sho)o(w)13
+b(last)h(10)f(commands)875 1396 y Ff(show)g(commands)e Fe(n)51
+b Fc(sho)o(w)13 b(10)g(commands)h(around)g(n)o(um)o(b)q(er)h
+Fe(n)875 1434 y Ff(show)e(commands)e(+)52 b Fc(sho)o(w)13 b(next)i(10)e
+(commands)875 1521 y Fg(W)l(orking)g(Files)875 1573 y Ff(file)g
+Fd([)p Fe(\014le)p Fd(])156 b Fc(use)14 b Fe(\014le)f Fc(for)h(b)q(oth)g(sym)
+o(b)q(ols)h(and)f(executable;)1206 1610 y(with)g(no)g(arg,)f(discard)h(b)q
+(oth)875 1659 y Ff(core)f Fd([)p Fe(\014le)p Fd(])156 b Fc(read)13
+b Fe(\014le)h Fc(as)f(coredump;)i(or)e(discard)875 1713 y Ff(exec)g
+Fd([)p Fe(\014le)p Fd(])156 b Fc(use)14 b Fe(\014le)f Fc(as)h(executable)g
+(only;)h(or)e(discard)875 1767 y Ff(symbol)f Fd([)p Fe(\014le)p
+Fd(])121 b Fc(use)14 b(sym)o(b)q(ol)h(table)f(from)g Fe(\014le)p
+Fc(;)f(or)h(discard)875 1810 y Ff(load)f Fe(\014le)180 b Fc(dynamically)15
+b(link)h Fe(\014le)f Fc(and)f(add)g(its)h(sym)o(b)q(ols)875
+1848 y Ff(add-sym)c Fe(\014le)j(addr)45 b Fc(read)13 b(additional)i(sym)o(b)q
+(ols)g(from)f Fe(\014le)p Fc(,)1206 1885 y(dynamically)h(loaded)f(at)f
+Fe(addr)875 1923 y Ff(info)g(files)135 b Fc(displa)o(y)15 b(w)o(orking)f
+(\014les)g(and)g(targets)f(in)i(use)875 1961 y Ff(path)e Fe(dirs)167
+b Fc(add)14 b Fe(dirs)f Fc(to)g(fron)o(t)h(of)g(path)g(searc)o(hed)f(for)1206
+1998 y(executable)g(and)h(sym)o(b)q(ol)h(\014les)875 2037 y
+Ff(show)e(path)153 b Fc(displa)o(y)15 b(executable)f(and)g(sym)o(b)q(ol)h
+(\014le)f(path)875 2074 y Ff(info)f(share)135 b Fc(list)15
+b(names)e(of)h(shared)g(libraries)h(curren)o(tly)1206 2111
+y(loaded)p 1900 -217 V 1900 2175 V 1975 -183 a Fg(Source)e(Files)1975
+-138 y Ff(dir)g Fe(names)148 b Fc(add)14 b(directory)g Fe(names)f
+Fc(to)h(fron)o(t)g(of)f(source)2306 -100 y(path)1975 -62 y
+Ff(dir)256 b Fc(clear)13 b(source)h(path)1975 -25 y Ff(show)f(dir)171
+b Fc(sho)o(w)14 b(curren)o(t)g(source)f(path)1975 50 y Ff(list)238
+b Fc(sho)o(w)14 b(next)g(ten)g(lines)h(of)e(source)1975 87
+y Ff(list)g(-)207 b Fc(sho)o(w)14 b(previous)g(ten)g(lines)1975
+125 y Ff(list)f Fe(lines)156 b Fc(displa)o(y)15 b(source)f(surrounding)h
+Fe(lines)p Fc(,)f(sp)q(eci\014ed)2306 162 y(as:)2011 206 y
+Fd([)p Fe(\014le)p Ff(:)p Fd(])p Fe(num)122 b Fc(line)15 b(n)o(um)o(b)q(er)g
+Fd([)p Fc(in)f(named)g(\014le)p Fd(])2011 260 y([)p Fe(\014le)p
+Ff(:)p Fd(])p Fe(function)63 b Fc(b)q(eginning)15 b(of)e(function)i
+Fd([)p Fc(in)f(named)g(\014le)p Fd(])2011 303 y Ff(+)p Fe(o\013)217
+b(o\013)14 b Fc(lines)h(after)e(last)h(prin)o(ted)2011 340
+y Ff(-)p Fe(o\013)217 b(o\013)14 b Fc(lines)h(previous)f(to)g(last)g(prin)o
+(ted)2011 377 y Ff(*)p Fe(addr)n(ess)145 b Fc(line)15 b(con)o(taining)f
+Fe(addr)n(ess)1975 415 y Ff(list)f Fe(f)p Ff(,)p Fe(l)187 b
+Fc(from)14 b(line)h Fe(f)e Fc(to)g(line)i Fe(l)1975 452 y Ff(info)e(line)f
+Fe(num)76 b Fc(sho)o(w)14 b(starting,)g(ending)g(addresses)g(of)2306
+489 y(compiled)g(co)q(de)f(for)h(source)f(line)i Fe(num)1975
+528 y Ff(info)e(source)117 b Fc(sho)o(w)14 b(name)f(of)h(curren)o(t)g(source)
+f(\014le)1975 565 y Ff(info)g(sources)99 b Fc(list)15 b(all)f(source)f
+(\014les)h(in)h(use)1975 603 y Ff(forw)e Fe(r)n(e)n(gex)150
+b Fc(searc)o(h)13 b(follo)o(wing)h(source)g(lines)h(for)e Fe(r)n(e)n(gex)1975
+640 y Ff(rev)g Fe(r)n(e)n(gex)168 b Fc(searc)o(h)13 b(preceding)h(source)g
+(lines)h(for)e Fe(r)n(e)n(gex)1975 737 y Fg(GDB)g(under)f(GNU)i(Emacs)1975
+782 y Ff(M-x)f(gdb)189 b Fc(run)14 b(GDB)g(under)h(Emacs)1975
+820 y Ff(C-h)e(m)225 b Fc(describ)q(e)14 b(GDB)g(mo)q(de)1975
+857 y Ff(M-s)256 b Fc(step)14 b(one)f(line)i(\()p Ff(step)p
+Fc(\))1975 899 y Ff(M-n)256 b Fc(next)14 b(line)h(\()p Ff(next)p
+Fc(\))1975 936 y Ff(M-i)256 b Fc(step)14 b(one)f(instruction)i(\()p
+Ff(stepi)p Fc(\))1975 978 y Ff(C-c)e(C-f)189 b Fc(\014nish)15
+b(curren)o(t)f(stac)o(k)g(frame)f(\()p Ff(finish)p Fc(\))1975
+1015 y Ff(M-c)256 b Fc(con)o(tin)o(ue)14 b(\()p Ff(cont)p Fc(\))1975
+1052 y Ff(M-u)256 b Fc(up)14 b Fe(ar)n(g)f Fc(frames)h(\()p
+Ff(up)p Fc(\))1975 1094 y Ff(M-d)256 b Fc(do)o(wn)14 b Fe(ar)n(g)f
+Fc(frames)h(\()p Ff(down)p Fc(\))1975 1131 y Ff(C-x)f(&)225
+b Fc(cop)o(y)14 b(n)o(um)o(b)q(er)h(from)f(p)q(oin)o(t,)h(insert)f(at)f(end)
+1975 1169 y Ff(C-x)g(SPC)189 b Fc(\(in)14 b(source)g(\014le\))g(set)f(break)h
+(at)g(p)q(oin)o(t)1975 1267 y Fg(GDB)f(License)1975 1313 y
+Ff(show)g(copying)99 b Fc(Displa)o(y)15 b(GNU)e(General)g(Public)i(License)
+1975 1350 y Ff(show)e(warranty)81 b Fc(There)13 b(is)i(NO)e(W)l(ARRANTY)g
+(for)h(GDB.)2306 1387 y(Displa)o(y)h(full)g(no-w)o(arran)o(t)o(y)f(statemen)o
+(t.)2024 1622 y Fh(Cop)o(yrigh)o(t)2185 1621 y(c)2171 1622
+y Fa(\015)o Fh(1991,)h(1992,)f(1993)h(F)n(ree)d(Soft)o(w)o(are)i(F)n
+(oundation,)f(Inc.)2215 1660 y(Roland)i(P)o(esc)o(h)f(\(p)q(esc)o(h@cygn)o
+(us.com\))1997 1697 y(The)f(author)h(assumes)f(no)h(resp)q(onsibilit)o(y)j
+(for)c(an)o(y)h(errors)g(on)g(this)h(card.)1975 1759 y(This)g(card)e(ma)o(y)g
+(b)q(e)g(freely)h(distributed)g(under)f(the)g(terms)g(of)g(the)h(GNU)1975
+1797 y(General)h(Public)g(License.)2012 1834 y(Please)f(con)o(tribute)g(to)g
+(dev)o(elopmen)o(t)e(of)i(this)h(card)e(b)o(y)h(annotating)h(it.)1975
+1896 y(GDB)g(itself)f(is)h(free)e(soft)o(w)o(are;)g(y)o(ou)h(are)g(w)o
+(elcome)e(to)i(distribute)h(copies)f(of)1975 1934 y(it)h(under)e(the)g(terms)
+g(of)g(the)g(GNU)i(General)g(Public)g(License.)20 b(There)12
+b(is)1975 1971 y(absolutely)k(no)d(w)o(arran)o(t)o(y)i(for)e(GDB.)p
+eop
+%%Trailer
+end
+userdict /end-hook known{end-hook}if
+%%EOF
diff --git a/gnu/usr.bin/gdb/doc/refcard.tex b/gnu/usr.bin/gdb/doc/refcard.tex
new file mode 100644
index 0000000..5899608
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/refcard.tex
@@ -0,0 +1,646 @@
+%%%%%%%%%%%%%%%% gdb-refcard.tex %%%%%%%%%%%%%%%%
+
+%This file is TeX source for a reference card describing GDB, the GNU debugger.
+%$Id: refcard.tex,v 1.1.1.1 1993/10/30 21:59:42 jkh Exp $
+%Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+%Permission is granted to make and distribute verbatim copies of
+%this reference provided the copyright notices and permission notices
+%are preserved on all copies.
+%
+%TeX markup is a programming language; accordingly this file is source
+%for a program to generate a reference.
+%
+%This program is free software; you can 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 can find a copy of the GNU General Public License in the GDB
+%manual; or write to the Free Software Foundation, Inc.,
+%675 Mass Ave, Cambridge, MA 02139, USA.
+%
+%You can contact the author as: pesch@cygnus.com
+%
+% Roland Pesch
+% Cygnus Support
+% 1937 Landings Drive
+% Mountain View, CA 94043 USA
+%
+% +1 415 903 1400
+%
+%
+%
+% 22-AUG-1993 Andreas Vogel
+%
+% Modifications made in order to handle different papersizes correctly.
+% You only have to set the total width and height of the paper, the
+% horizontal and vertical margin space measured from *paper edge*
+% and the interline and interspec spacing.
+% In order to support a new papersize, you have to fiddle with the
+% latter four dimensions. Just try out a few values.
+% All other values will be computed at process time so it should be
+% quite easy to support different paper sizes - only four values to
+% guess :-)
+%
+% To find the configuration places, just search for the string
+% "CONFIGURATION".
+%
+% Andreas Vogel (av@ssw.de)
+%
+%
+%
+% Uncomment the following `magnification' command if you want to print
+% out in a larger font. Caution! You may need larger paper. You had
+% best avoid using 3-column output if you try this. See the ``Three
+% column format'' section below if you want to print in three column
+% format.
+%
+%\magnification=\magstep 1
+%
+% NOTE ON INTENTIONAL OMISSIONS: This reference card includes most GDB
+% commands, but due to space constraints there are some things I chose
+% to omit. In general, not all synonyms for commands are covered, nor
+% all variations of a command.
+% The GDB-under-Emacs section omits gdb-mode functions without default
+% keybindings. GDB startup options are not described.
+% set print sevenbit-strings, set symbol-reloading omitted.
+% printsyms, printpsyms, omitted since they're for GDB maintenance primarily
+% share omitted due to obsolescence
+% set check range/type omitted at least til code is in GDB.
+%
+%-------------------- Three column format -----------------------
+
+%%%% --- To disable three column format, comment out this entire section
+
+% Three-column format for landscape printing
+
+%-------- Papersize defs:
+
+\newdimen\totalwidth \newdimen\totalheight
+\newdimen\hmargin \newdimen\vmargin
+\newdimen\secskip \newdimen\lskip
+\newdimen\barwidth \newdimen\barheight
+\newdimen\intersecwidth
+
+%%
+%% START CONFIGURATION - PAPERSIZE DEFINITIONS
+%------- Papersize params:
+%% US letter paper (8.5x11in)
+%%
+\totalwidth=11in % total width of paper
+\totalheight=8.5in % total height of paper
+\hmargin=.25in % horizontal margin width
+\vmargin=.25in % vertical margin width
+\secskip=1pc % space between refcard secs
+\lskip=2pt % extra skip between \sec entries
+%------- end papersize params
+%%
+%% change according to personal taste, not papersize dependent
+%%
+\barwidth=.1pt % width of the cropmark bar
+\barheight=2pt % height of the cropmark bar
+\intersecwidth=0.5em % width between \itmwid and \dfnwid
+%%
+%% END CONFIGURATION - PAPERSIZE DEFINITIONS
+%%
+
+%%
+%% values to be computed - nothing to configure
+%%
+\newdimen\fullhsize % width of area without margins
+\newdimen\itmwid % width of item column
+\newdimen\dfnwid % width of definition column
+\newdimen\temp % only for temporary use
+
+%%
+%% adjust the offsets so the margins are measured *from paper edge*
+%%
+\hoffset=-1in \advance \hoffset by \hmargin
+\voffset=-1in \advance \voffset by \vmargin
+
+%%
+%% fullhsize = totalwidth - (2 * hmargin)
+%%
+\fullhsize=\totalwidth
+\temp=\hmargin \multiply \temp by 2 \advance \fullhsize by -\temp
+
+%%
+%% hsize = (fullhsize - (4 * hmargin) - (2 * barwidth)) / 3
+%%
+\hsize=\fullhsize
+\temp=\hmargin \multiply \temp by 4 \advance \hsize by -\temp
+\temp=\barwidth \multiply \temp by 2 \advance \hsize by -\temp
+\divide \hsize by 3
+
+%%
+%% vsize = totalheight - (2 * vmargin)
+%%
+\vsize=\totalheight
+\temp=\vmargin \multiply \temp by 2 \advance \vsize by -\temp
+
+%%
+%% itmwid = (hsize - intersecwidth) * 1/3
+%% dfnwid = (hsize - intersecwidth) * 2/3
+%%
+\temp=\hsize \advance \temp by -\intersecwidth \divide \temp by 3
+\itmwid=\temp
+\dfnwid=\hsize \advance \dfnwid by -\itmwid
+
+%-------- end papersize defs
+
+
+\def\fulline{\hbox to \fullhsize}
+\let\lcr=L \newbox\leftcolumn\newbox\centercolumn
+\output={\if L\lcr
+ \global\setbox\leftcolumn=\columnbox \global\let\lcr=C
+ \else
+ \if C\lcr
+ \global\setbox\centercolumn=\columnbox \global\let\lcr=R
+ \else \tripleformat \global\let\lcr=L
+ \fi
+ \fi
+% \ifnum\outputpenalty>-20000 \else\dosupereject\fi
+ }
+
+%%
+%% START CONFIGURATION - ALTERNATIVE FOLDING GUIDES
+%%
+%% For NO printed folding guide,
+%% comment out other \def\vdecor's and uncomment:
+
+%\def\vdecor{\hskip\hmargin plus1fil\hskip\barwidth plus1fil\hskip\hmargin plus1fil}
+
+%% For SOLID LINE folding guide,
+%% comment out other \def\vdecor's and uncomment:
+
+%\def\vdecor{\hskip\hmargin plus1fil \vrule width \barwidth \hskip\hmargin plus1fil}
+
+%% For SMALL MARKS NEAR TOP AND BOTTOM as folding guide,
+%% comment out other \def\vdecor's and uncomment:
+
+\def\vdecor{\hskip\hmargin plus1fil
+\vbox to \vsize{\hbox to \barwidth{\vrule height\barheight width\barwidth}\vfill
+\hbox to \barwidth{\vrule height\barheight width\barwidth}}%THIS PERCENT SIGN IS ESSENTIAL
+\hskip\hmargin plus1fil}
+
+%%
+%% END CONFIGURATION - ALTERNATIVES FOR FOLDING GUIDES
+%%
+
+\def\tripleformat{\shipout\vbox{\fulline{\box\leftcolumn\vdecor
+ \box\centercolumn\vdecor
+ \columnbox}
+ }
+ \advancepageno}
+\def\columnbox{\leftline{\pagebody}}
+\def\bye{\par\vfill
+ \supereject
+ \if R\lcr \null\vfill\eject\fi
+ \end}
+
+%-------------------- end three column format -----------------------
+
+%-------------------- Computer Modern font defs: --------------------
+\font\bbf=cmbx10
+\font\vbbf=cmbx12
+\font\smrm=cmr6
+\font\brm=cmr10
+\font\rm=cmr7
+\font\it=cmti7
+\font\tt=cmtt8
+%-------------------- end font defs ---------------------------------
+
+%
+\hyphenpenalty=5000\tolerance=2000\raggedright\raggedbottom
+\normalbaselineskip=9pt\baselineskip=9pt
+%
+\parindent=0pt
+\parskip=0pt
+\footline={\vbox to0pt{\hss}}
+%
+\def\ctl#1{{\tt C-#1}}
+\def\opt#1{{\brm[{\rm #1}]}}
+\def\xtra#1{\noalign{\smallskip{\tt#1}}}
+%
+\long\def\sec#1;#2\endsec{\vskip \secskip
+\halign{%
+%COL 1 (of halign):
+\vtop{\hsize=\itmwid\tt
+##\par\vskip \lskip }\hfil
+%COL 2 (of halign):
+&\vtop{\hsize=\dfnwid\hangafter=1\hangindent=\intersecwidth
+\rm ##\par\vskip \lskip}\cr
+%Tail of \long\def fills in halign body with \sec args:
+\noalign{{\bbf #1}\vskip \lskip}
+#2
+}
+}
+
+{\vbbf GDB QUICK REFERENCE}\hfil{\smrm GDB Version 4}\qquad
+
+\sec Essential Commands;
+gdb {\it program} \opt{{\it core}}&debug {\it program} \opt{using
+coredump {\it core}}\cr
+b \opt{\it file\tt:}{\it function}&set breakpoint at {\it function} \opt{in \it file}\cr
+run \opt{{\it arglist}}&start your program \opt{with {\it arglist}}\cr
+bt& backtrace: display program stack\cr
+p {\it expr}&display the value of an expression\cr
+c &continue running your program\cr
+n &next line, stepping over function calls\cr
+s &next line, stepping into function calls\cr
+\endsec
+
+\sec Starting GDB;
+gdb&start GDB, with no debugging files\cr
+gdb {\it program}&begin debugging {\it program}\cr
+gdb {\it program core}&debug coredump {\it core} produced by {\it
+program}\cr
+gdb --help&describe command line options\cr
+\endsec
+
+\sec Stopping GDB;
+quit&exit GDB; also {\tt q} or {\tt EOF} (eg \ctl{d})\cr
+INTERRUPT&(eg \ctl{c}) terminate current command, or send to running process\cr
+\endsec
+
+\sec Getting Help;
+help&list classes of commands\cr
+help {\it class}&one-line descriptions for commands in {\it class}\cr
+help {\it command}&describe {\it command}\cr
+\endsec
+
+\sec Executing your Program;
+run {\it arglist}&start your program with {\it arglist}\cr
+run&start your program with current argument list\cr
+run $\ldots$ <{\it inf} >{\it outf}&start your program with input, output
+redirected\cr
+\cr
+kill&kill running program\cr
+\cr
+tty {\it dev}&use {\it dev} as stdin and stdout for next {\tt run}\cr
+set args {\it arglist}&specify {\it arglist} for next
+{\tt run}\cr
+set args&specify empty argument list\cr
+show args&display argument list\cr
+\cr
+show environment&show all environment variables\cr
+show env {\it var}&show value of environment variable {\it var}\cr
+set env {\it var} {\it string}&set environment variable {\it var}\cr
+unset env {\it var}&remove {\it var} from environment\cr
+\endsec
+
+\sec Shell Commands;
+cd {\it dir}&change working directory to {\it dir}\cr
+pwd&Print working directory\cr
+make $\ldots$&call ``{\tt make}''\cr
+shell {\it cmd}&execute arbitrary shell command string\cr
+\endsec
+
+\vfill
+\line{\smrm \opt{ } surround optional arguments \hfill $\ldots$ show
+one or more arguments}
+\vskip\baselineskip
+\centerline{\smrm \copyright 1991, 1992 Free Software Foundation, Inc.\qquad Permissions on back}
+\eject
+\sec Breakpoints and Watchpoints;
+break \opt{\it file\tt:}{\it line}\par
+b \opt{\it file\tt:}{\it line}&set breakpoint at {\it line} number \opt{in \it file}\par
+eg:\quad{\tt break main.c:37}\quad\cr
+break \opt{\it file\tt:}{\it func}&set breakpoint at {\it
+func} \opt{in \it file}\cr
+break +{\it offset}\par
+break -{\it offset}&set break at {\it offset} lines from current stop\cr
+break *{\it addr}&set breakpoint at address {\it addr}\cr
+break&set breakpoint at next instruction\cr
+break $\ldots$ if {\it expr}&break conditionally on nonzero {\it expr}\cr
+cond {\it n} \opt{\it expr}&new conditional expression on breakpoint
+{\it n}; make unconditional if no {\it expr}\cr
+tbreak $\ldots$&temporary break; disable when reached\cr
+rbreak {\it regex}&break on all functions matching {\it regex}\cr
+watch {\it expr}&set a watchpoint for expression {\it expr}\cr
+catch {\it x}&break at C++ handler for exception {\it x}\cr
+\cr
+info break&show defined breakpoints\cr
+info watch&show defined watchpoints\cr
+\cr
+clear&delete breakpoints at next instruction\cr
+clear \opt{\it file\tt:}{\it fun}&delete breakpoints at entry to {\it fun}()\cr
+clear \opt{\it file\tt:}{\it line}&delete breakpoints on source line \cr
+delete \opt{{\it n}}&delete breakpoints
+\opt{or breakpoint {\it n}}\cr
+\cr
+disable \opt{{\it n}}&disable breakpoints
+\opt{or breakpoint {\it n}}
+\cr
+enable \opt{{\it n}}&enable breakpoints
+\opt{or breakpoint {\it n}}
+\cr
+enable once \opt{{\it n}}&enable breakpoints \opt{or breakpoint {\it n}};
+disable again when reached
+\cr
+enable del \opt{{\it n}}&enable breakpoints \opt{or breakpoint {\it n}};
+delete when reached
+\cr
+\cr
+ignore {\it n} {\it count}&ignore breakpoint {\it n}, {\it count}
+times\cr
+\cr
+commands {\it n}\par
+\qquad \opt{\tt silent}\par
+\qquad {\it command-list}&execute GDB {\it command-list} every time breakpoint {\it n} is reached. \opt{{\tt silent} suppresses default
+display}\cr
+end&end of {\it command-list}\cr
+\endsec
+
+\sec Program Stack;
+backtrace \opt{\it n}\par
+bt \opt{\it n}&print trace of all frames in stack; or of {\it n}
+frames---innermost if {\it n}{\tt >0}, outermost if {\it n}{\tt <0}\cr
+frame \opt{\it n}&select frame number {\it n} or frame at address {\it
+n}; if no {\it n}, display current frame\cr
+up {\it n}&select frame {\it n} frames up\cr
+down {\it n}&select frame {\it n} frames down\cr
+info frame \opt{\it addr}&describe selected frame, or frame at
+{\it addr}\cr
+info args&arguments of selected frame\cr
+info locals&local variables of selected frame\cr
+info reg \opt{\it rn}$\ldots$\par
+info all-reg \opt{\it rn}&register values \opt{for regs {\it rn\/}} in
+selected frame; {\tt all-reg} includes floating point\cr
+info catch&exception handlers active in selected frame\cr
+\endsec
+
+\vfill\eject
+\sec Execution Control;
+continue \opt{\it count}\par
+c \opt{\it count}&continue running; if {\it count} specified, ignore
+this breakpoint next {\it count} times\cr
+\cr
+step \opt{\it count}\par
+s \opt{\it count}&execute until another line reached; repeat {\it count} times if
+specified\cr
+stepi \opt{\it count}\par
+si \opt{\it count}&step by machine instructions rather than source
+lines\cr
+\cr
+next \opt{\it count}\par
+n \opt{\it count}&execute next line, including any function calls\cr
+nexti \opt{\it count}\par
+ni \opt{\it count}&next machine instruction rather than source
+line\cr
+\cr
+until \opt{\it location}&run until next instruction (or {\it
+location})\cr
+finish&run until selected stack frame returns\cr
+return \opt{\it expr}&pop selected stack frame without executing
+\opt{setting return value}\cr
+signal {\it num}&resume execution with signal {\it s} (none if {\tt 0})\cr
+jump {\it line}\par
+jump *{\it address}&resume execution at specified {\it line} number or
+{\it address}\cr
+set var={\it expr}&evaluate {\it expr} without displaying it; use for
+altering program variables\cr
+\endsec
+
+\sec Display;
+print \opt{\tt/{\it f}\/} \opt{\it expr}\par
+p \opt{\tt/{\it f}\/} \opt{\it expr}&show value of {\it expr} \opt{or
+last value \tt \$} according to format {\it f}:\cr
+\qquad x&hexadecimal\cr
+\qquad d&signed decimal\cr
+\qquad u&unsigned decimal\cr
+\qquad o&octal\cr
+\qquad t&binary\cr
+\qquad a&address, absolute and relative\cr
+\qquad c&character\cr
+\qquad f&floating point\cr
+call \opt{\tt /{\it f}\/} {\it expr}&like {\tt print} but does not display
+{\tt void}\cr
+x \opt{\tt/{\it Nuf}\/} {\it expr}&examine memory at address {\it expr};
+optional format spec follows slash\cr
+\quad {\it N}&count of how many units to display\cr
+\quad {\it u}&unit size; one of\cr
+&{\tt\qquad b}\ individual bytes\cr
+&{\tt\qquad h}\ halfwords (two bytes)\cr
+&{\tt\qquad w}\ words (four bytes)\cr
+&{\tt\qquad g}\ giant words (eight bytes)\cr
+\quad {\it f}&printing format. Any {\tt print} format, or\cr
+&{\tt\qquad s}\ null-terminated string\cr
+&{\tt\qquad i}\ machine instructions\cr
+disassem \opt{\it addr}&display memory as machine instructions\cr
+\endsec
+
+\sec Automatic Display;
+display \opt{\tt/\it f\/} {\it expr}&show value of {\it expr} each time
+program stops \opt{according to format {\it f}\/}\cr
+display&display all enabled expressions on list\cr
+undisplay {\it n}&remove number(s) {\it n} from list of
+automatically displayed expressions\cr
+disable disp {\it n}&disable display for expression(s) number {\it
+n}\cr
+enable disp {\it n}&enable display for expression(s) number {\it
+n}\cr
+info display&numbered list of display expressions\cr
+\endsec
+
+\vfill\eject
+
+\sec Expressions;
+{\it expr}&an expression in C, C++, or Modula-2 (including function calls), or:\cr
+{\it addr\/}@{\it len}&an array of {\it len} elements beginning at {\it
+addr}\cr
+{\it file}::{\it nm}&a variable or function {\it nm} defined in {\it
+file}\cr
+$\tt\{${\it type}$\tt\}${\it addr}&read memory at {\it addr} as specified
+{\it type}\cr
+\$&most recent displayed value\cr
+\${\it n}&{\it n}th displayed value\cr
+\$\$&displayed value previous to \$\cr
+\$\${\it n}&{\it n}th displayed value back from \$\cr
+\$\_&last address examined with {\tt x}\cr
+\$\_\_&value at address \$\_\cr
+\${\it var}&convenience variable; assign any value\cr
+\cr
+show values \opt{{\it n}}&show last 10 values \opt{or surrounding
+\${\it n}}\cr
+show convenience&display all convenience variables\cr
+\endsec
+
+\sec Symbol Table;
+info address {\it s}&show where symbol {\it s} is stored\cr
+info func \opt{\it regex}&show names, types of defined functions
+(all, or matching {\it regex})\cr
+info var \opt{\it regex}&show names, types of global variables (all,
+or matching {\it regex})\cr
+whatis \opt{\it expr}\par
+ptype \opt{\it expr}&show data type of {\it expr} \opt{or \tt \$}
+without evaluating; {\tt ptype} gives more detail\cr
+ptype {\it type}&describe type, struct, union, or enum\cr
+\endsec
+
+\sec GDB Scripts;
+source {\it script}&read, execute GDB commands from file {\it
+script}\cr
+\cr
+define {\it cmd}\par
+\qquad {\it command-list}&create new GDB command {\it cmd};
+execute script defined by {\it command-list}\cr
+end&end of {\it command-list}\cr
+document {\it cmd}\par
+\qquad {\it help-text}&create online documentation
+for new GDB command {\it cmd}\cr
+end&end of {\it help-text}\cr
+\endsec
+
+\sec Signals;
+handle {\it signal} {\it act}&specify GDB actions for {\it signal}:\cr
+\quad print&announce signal\cr
+\quad noprint&be silent for signal\cr
+\quad stop&halt execution on signal\cr
+\quad nostop&do not halt execution\cr
+\quad pass&allow your program to handle signal\cr
+\quad nopass&do not allow your program to see signal\cr
+info signals&show table of signals, GDB action for each\cr
+\endsec
+
+\sec Debugging Targets;
+target {\it type} {\it param}&connect to target machine, process, or file\cr
+help target&display available targets\cr
+attach {\it param}&connect to another process\cr
+detach&release target from GDB control\cr
+\endsec
+
+\vfill\eject
+\sec Controlling GDB;
+set {\it param} {\it value}&set one of GDB's internal parameters\cr
+show {\it param}&display current setting of parameter\cr
+\xtra{\rm Parameters understood by {\tt set} and {\tt show}:}
+\quad complaints {\it limit}&number of messages on unusual symbols\cr
+\quad confirm {\it on/off}&enable or disable cautionary queries\cr
+\quad editing {\it on/off}&control {\tt readline} command-line editing\cr
+\quad height {\it lpp}&number of lines before pause in display\cr
+\quad language {\it lang}&Language for GDB expressions ({\tt auto}, {\tt c} or
+{\tt modula-2})\cr
+\quad listsize {\it n}&number of lines shown by {\tt list}\cr
+\quad prompt {\it str}&use {\it str} as GDB prompt\cr
+\quad radix {\it base}&octal, decimal, or hex number representation\cr
+\quad verbose {\it on/off}&control messages when loading
+symbols\cr
+\quad width {\it cpl}&number of characters before line folded\cr
+\quad write {\it on/off}&Allow or forbid patching binary, core files
+(when reopened with {\tt exec} or {\tt core})
+\cr
+\quad history $\ldots$\par
+\quad h $\ldots$&groups with the following options:\cr
+\quad h exp {\it off/on}&disable/enable {\tt readline} history expansion\cr
+\quad h file {\it filename}&file for recording GDB command history\cr
+\quad h size {\it size}&number of commands kept in history list\cr
+\quad h save {\it off/on}&control use of external file for
+command history\cr
+\cr
+\quad print $\ldots$\par
+\quad p $\ldots$&groups with the following options:\cr
+\quad p address {\it on/off}&print memory addresses in stacks,
+values\cr
+\quad p array {\it off/on}&compact or attractive format for
+arrays\cr
+\quad p demangl {\it on/off}&source (demangled) or internal form for C++
+symbols\cr
+\quad p asm-dem {\it on/off}&demangle C++ symbols in
+machine-instruction output\cr
+\quad p elements {\it limit}&number of array elements to display\cr
+\quad p object {\it on/off}&print C++ derived types for objects\cr
+\quad p pretty {\it off/on}&struct display: compact or indented\cr
+\quad p union {\it on/off}&display of union members\cr
+\quad p vtbl {\it off/on}&display of C++ virtual function
+tables\cr
+\cr
+show commands&show last 10 commands\cr
+show commands {\it n}&show 10 commands around number {\it n}\cr
+show commands +&show next 10 commands\cr
+\endsec
+
+\sec Working Files;
+file \opt{\it file}&use {\it file} for both symbols and executable;
+with no arg, discard both\cr
+core \opt{\it file}&read {\it file} as coredump; or discard\cr
+exec \opt{\it file}&use {\it file} as executable only; or discard\cr
+symbol \opt{\it file}&use symbol table from {\it file}; or discard\cr
+load {\it file}&dynamically link {\it file\/} and add its symbols\cr
+add-sym {\it file} {\it addr}&read additional symbols from {\it file},
+dynamically loaded at {\it addr}\cr
+info files&display working files and targets in use\cr
+path {\it dirs}&add {\it dirs} to front of path searched for
+executable and symbol files\cr
+show path&display executable and symbol file path\cr
+info share&list names of shared libraries currently loaded\cr
+\endsec
+
+\vfill\eject
+\sec Source Files;
+dir {\it names}&add directory {\it names} to front of source path\cr
+dir&clear source path\cr
+show dir&show current source path\cr
+\cr
+list&show next ten lines of source\cr
+list -&show previous ten lines\cr
+list {\it lines}&display source surrounding {\it lines},
+specified as:\cr
+\quad{\opt{\it file\tt:}\it num}&line number \opt{in named file}\cr
+\quad{\opt{\it file\tt:}\it function}&beginning of function \opt{in
+named file}\cr
+\quad{\tt +\it off}&{\it off} lines after last printed\cr
+\quad{\tt -\it off}&{\it off} lines previous to last printed\cr
+\quad{\tt*\it address}&line containing {\it address}\cr
+list {\it f},{\it l}&from line {\it f} to line {\it l}\cr
+info line {\it num}&show starting, ending addresses of compiled code for
+source line {\it num}\cr
+info source&show name of current source file\cr
+info sources&list all source files in use\cr
+forw {\it regex}&search following source lines for {\it regex}\cr
+rev {\it regex}&search preceding source lines for {\it regex}\cr
+\endsec
+
+\sec GDB under GNU Emacs;
+M-x gdb&run GDB under Emacs\cr
+\ctl{h} m&describe GDB mode\cr
+M-s&step one line ({\tt step})\cr
+M-n&next line ({\tt next})\cr
+M-i&step one instruction ({\tt stepi})\cr
+\ctl{c} \ctl{f}&finish current stack frame ({\tt finish})\cr
+M-c&continue ({\tt cont})\cr
+M-u&up {\it arg} frames ({\tt up})\cr
+M-d&down {\it arg} frames ({\tt down})\cr
+\ctl{x} \&&copy number from point, insert at end\cr
+\ctl{x} SPC&(in source file) set break at point\cr
+\endsec
+
+\sec GDB License;
+show copying&Display GNU General Public License\cr
+show warranty&There is NO WARRANTY for GDB. Display full no-warranty
+statement.\cr
+\endsec
+
+
+\vfill
+{\smrm\parskip=6pt
+\centerline{Copyright \copyright 1991, 1992, 1993 Free Software Foundation, Inc.}
+\centerline{Roland Pesch (pesch@cygnus.com)}
+\centerline{The author assumes no responsibility for any errors on this card.}
+
+This card may be freely distributed under the terms of the GNU
+General Public License.
+
+\centerline{Please contribute to development of this card by
+annotating it.}
+
+GDB itself is free software; you are welcome to distribute copies of
+it under the terms of the GNU General Public License. There is
+absolutely no warranty for GDB.
+}
+\end
diff --git a/gnu/usr.bin/gdb/doc/remote.texi b/gnu/usr.bin/gdb/doc/remote.texi
new file mode 100644
index 0000000..5b7ec90
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/remote.texi
@@ -0,0 +1,1294 @@
+@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 680x0
+For Motorola 680x0 architectures.
+
+@item i386-stub.c
+@kindex i386-stub.c
+@cindex Intel
+@cindex 386
+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 will transfer 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 will get 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. To allow the stub to work, you must supply
+these special low-level subroutines:
+
+@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.
+
+@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,
+etc.) 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 will vary 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 Outline of the 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}.
+
+@item c
+@itemx c@var{addr}
+Resume execution at the current address (or at @var{addr} if supplied).
+
+@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} will show 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
+@var{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 @var{GDBN}, so you may be able to get
+started more quickly on a new system by using @code{gdbserver}.
+
+@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,
+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{GDB};
+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.@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 host,
+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
+@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 descriptof 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 @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 @value{GDBN} and 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 @value{GDBN} and 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} will keep
+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} will @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
+
+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} will read 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 will get 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.
+
+The remote debugging interface (RDB) routines are installed and executed
+on the VxWorks target. These routines are included in the VxWorks library
+@file{rdb.a} and are incorporated into the system image when source-level
+debugging is enabled in the VxWorks configuration.
+
+@kindex INCLUDE_RDB
+If you wish, you can define @code{INCLUDE_RDB} in the VxWorks
+configuration file @file{configAll.h} to include the RDB interface
+routines and spawn 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 the RDB interface 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
+
+@value{GDBN} displays messages like these:
+
+@smallexample
+Attaching remote machine across net...
+Connected to tt.
+@end smallexample
+
+@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 will cause @value{GDBN} to 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. If running, it will be 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 (this 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);
+
+@ignore
+@c this is only for Unix hosts, not currently of interest.
+@item
+what speed to use over the serial device.
+@end ignore
+@end enumerate
+
+@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} will see the effect of a @sc{reset} on the
+development board as a ``normal exit'' of your program.
+@end ifset
+@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}.
+
+@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.
+
+You can also specify @var{port} as a TCP connection (for instance, to a
+serial line managed by a terminal concentrator), using the syntax
+@code{@var{hostname}:@var{portnumber}}.
+
+@cindex @code{remotedebug}, MIPS 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 1 using
+@samp{set remotedebug 1} every packet will be displayed. If you set it
+to 2 every character will be displayed. You can check the current value
+at any time with the command @samp{show remotedebug}.
+
+@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}.)
+
+@kindex set mipsfpu off
+@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} (you may
+wish to put this 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.
+@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 will suspend 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..23d8e7b
--- /dev/null
+++ b/gnu/usr.bin/gdb/doc/stabs.texinfo
@@ -0,0 +1,3795 @@
+\input texinfo
+@setfilename stabs.info
+
+@c @finalout
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* 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: 1.1.1.1 $} % 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
+* Stabs In ELF:: Stabs in an ELF file.
+* 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
+@c FIXME! <<name of inventor>> 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.
+
+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 explictly 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.
+@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.
+
+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 s@var{size}
+Size in bits of a variable 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.
+@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 cretinously limit the strings to
+about 80 characters, so compilers which must work with such dbx's need
+to split the @code{.stabs} directive into several @code{.stabs}
+directives. Each stab duplicates exactly all but the
+string field. The string field of
+every stab except the last is marked as continued with a
+double-backslash at the end. Removing the backslashes and concatenating
+the string fields of each stab produces the original,
+long string.
+
+@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::
+@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 Sun's stabs-in-ELF, 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 @code{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. See @ref{Stabs In ELF} 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
+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 Sun's stabs-in-ELF, 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 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.
+
+@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.
+
+@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, each symbol has a section number, so the stab type
+need not indicate the section.
+
+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{Stabs In ELF}.
+
+@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.
+
+@findex N_LSYM, for parameter
+Some compilers use the pair of symbols approach described above
+(@samp{@var{arg}:p} followed by @samp{@var{arg}:}); this includes GCC1
+(not GCC2) on the sparc when passing a small structure and GCC2
+(sometimes) when the argument type is @code{float} and it is passed as a
+@code{double} and converted to @code{float} by the prologue (in the
+latter case the type of the @samp{@var{arg}:p} symbol is @code{double}
+and the type of the @samp{@var{arg}:} symbol is @code{float}).
+
+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. How is the truth value encoded? Is it
+the least significant bit or is it a question of whether the whole value
+is zero or non-zero?
+
+@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}.
+
+@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{:}.
+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
+
+@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{;}.
+
+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). There should be a way to specify an enumeration type of
+another size; type attributes would be one way to do this. @xref{Stabs
+Format}.
+
+@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.
+
+@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::
+* ELF Transformations:: In ELF, 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 ELF Transformations
+@subsection Transformations of Stabs in ELF Files
+
+For ELF files, 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{Stabs In ELF}). 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
+* Basic Cplusplus Types::
+* Simple Classes::
+* Class Instance::
+* Methods:: Method definition
+* Protections::
+* Method Modifiers::
+* Virtual Methods::
+* Inheritence::
+* Virtual Base Classes::
+* Static Members::
+@end menu
+
+Type descriptors added for C++ descriptions:
+
+@table @code
+@item #
+method type (@code{##} if minimal debug)
+
+@item @@
+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.
+@end table
+
+@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 descriptor
+@samp{#}, indicating a method type, and a second @samp{#}, indicating
+that this is the @dfn{minimal} type of method definition used by GCC2,
+not larger method definitions used by earlier versions of GCC. This is
+followed by a type reference showing the return type of the method and a
+semi-colon.
+
+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 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.
+
+@c FIXME: What does "part of the string" mean?
+Protections for class member data are signified by two characters
+embedded in the stab defining the class type. These characters are
+located after the name: part of the string. @samp{/0} means private,
+@samp{/1} means protected, and @samp{/2} means public. If these
+characters are omited this means that the member is public. The
+following C++ source:
+
+@example
+class all_data @{
+private:
+ int priv_dat;
+protected:
+ char prot_dat;
+public:
+ float pub_dat;
+@};
+@end example
+
+@noindent
+generates the following stab to describe the class type all_data.
+
+@display
+.stabs "class_name:sym_desc(type)type_def(19)=type_desc(struct)struct_bytes
+ data_name:/protection(private)type_ref(int),bit_offset,num_bits;
+ data_name:/protection(protected)type_ref(char),bit_offset,num_bits;
+ data_name:(/num omited, private)type_ref(float),bit_offset,num_bits;;"
+ N_LSYM,NIL,NIL,NIL
+@end display
+
+@smallexample
+.stabs "all_data:t19=s12
+ priv_dat:/01,0,32;prot_dat:/12,32,8;pub_dat:12,64,32;;",128,0,0,0
+@end smallexample
+
+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: two digits, a number,
+a comma, another number, and a semi-colon.
+
+The first of the two digits is 1 if the base class is virtual and 0 if
+not. The second digit is 2 if the derivation is public and 0 if not.
+
+The number following the first two digits 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
+@code{a.out} files, in numeric order. This does not apply to XCOFF, but
+it does apply to stabs in ELF. 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
+Absolute set element
+
+@item 0x16 N_SETT
+Text segment set element
+
+@item 0x18 N_SETD
+Data segment set element
+
+@item 0x1a N_SETB
+BSS segment set element
+
+@item 0x1c N_SETV
+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{N_ENTRY}.
+
+@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 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 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{Cplusplus}.
+
+@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{Cplusplus}.
+
+@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}.
+
+@item B
+Volatile-qualified type; see @ref{Miscellaneous Types}.
+
+@item c
+Complex builtin type; see @ref{Builtin Type Descriptors}.
+
+@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; see @ref{Cross-References}.
+
+@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 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. @samp{#} stands in for the type descriptor.
+
+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_ENTRY:: Alternate entry point
+* 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
+@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_ENTRY
+@section N_ENTRY
+
+@deffn @code{.stabn} N_ENTRY
+@findex N_ENTRY
+Alternate entry point.
+The value is its address.
+<<?>>
+@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: Get C_* types for the block, figure out whether it is always
+@c used (I suspect not), explain clearly, and move to node Statics.
+Exception: initialised static @code{N_STSYM} and un-initialized static
+@code{N_LCSYM} both map to the @code{C_STSYM} storage class. But the
+distinction is preserved because in XCOFF @code{N_STSYM} and
+@code{N_LCSYM} must be emited in a named static block. Begin the block
+with @samp{.bs s[RW] data_section_name} for @code{N_STSYM} or @samp{.bs
+s bss_section_name} for @code{N_LCSYM}. End the block with @samp{.es}.
+
+@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 Stabs In ELF
+@appendix Using Stabs With The ELF Object File Format
+
+The ELF object file format allows tools to create object files with
+custom sections containing any arbitrary data. To use stabs in ELF
+object files, the tools create 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 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.
+
+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.
+
+@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.
+
+To keep linking fast, it is a bad idea to have the linker relocating
+stabs, so (except for a few cases, see below) none of the addresses in
+the @code{n_value} field of the stabs are relocated by the linker.
+Instead they are relative to the source file (or some entity smaller
+than a source file, like a function). 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{ELF Transformations}. GCC
+does not provide these symbols; it instead relies on the stabs getting
+relocated, which slows down linking. 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. 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.
+
+@node Symbol Types Index
+@unnumbered Symbol Types Index
+
+@printindex fn
+
+@contents
+@bye
diff --git a/gnu/usr.bin/gdb/environ.c b/gnu/usr.bin/gdb/environ.c
new file mode 100644
index 0000000..0220166
--- /dev/null
+++ b/gnu/usr.bin/gdb/environ.c
@@ -0,0 +1,185 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)environ.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* 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 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. */
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+#include "environ.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;
+
+ for (i = 0; environ[i]; i++);
+
+ if (e->allocated < i)
+ {
+ e->allocated = max (i, e->allocated + 10);
+ e->vector = (char **) xrealloc (e->vector,
+ (e->allocated + 1) * sizeof (char *));
+ }
+
+ bcopy (environ, e->vector, (i + 1) * sizeof (char *));
+
+ while (--i >= 0)
+ {
+ register int len = strlen (e->vector[i]) + 1;
+ register char *new = (char *) xmalloc (len);
+ bcopy (e->vector[i], new, len);
+ 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)
+ struct environ *e;
+ char *var;
+{
+ register int len = strlen (var);
+ register char **vector = e->vector;
+ register char *s;
+
+ for (; s = *vector; vector++)
+ if (!strncmp (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;
+ char *var;
+ char *value;
+{
+ register int i;
+ register int len = strlen (var);
+ register char **vector = e->vector;
+ register char *s;
+
+ for (i = 0; s = vector[i]; i++)
+ if (!strncmp (s, var, len)
+ && s[len] == '=')
+ break;
+
+ if (s == 0)
+ {
+ if (i == e->allocated)
+ {
+ e->allocated += 10;
+ vector = (char **) xrealloc (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;
+ 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; vector++)
+ if (!strncmp (s, var, len)
+ && s[len] == '=')
+ {
+ free (s);
+ bcopy (vector + 1, vector,
+ (e->allocated - (vector - e->vector)) * sizeof (char *));
+ e->vector[e->allocated - 1] = 0;
+ return;
+ }
+}
diff --git a/gnu/usr.bin/gdb/environ.h b/gnu/usr.bin/gdb/environ.h
new file mode 100644
index 0000000..13f31f4
--- /dev/null
+++ b/gnu/usr.bin/gdb/environ.h
@@ -0,0 +1,39 @@
+/* Header for environment manipulation library.
+ Copyright (C) 1989, 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 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. */
+
+/* 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;
+};
+
+struct environ *make_environ ();
+void free_environ ();
+void init_environ ();
+char *get_in_environ ();
+void set_in_environ ();
+void unset_in_environ ();
+char **environ_vector ();
diff --git a/gnu/usr.bin/gdb/eval.c b/gnu/usr.bin/gdb/eval.c
new file mode 100644
index 0000000..60779e6
--- /dev/null
+++ b/gnu/usr.bin/gdb/eval.c
@@ -0,0 +1,1065 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)eval.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Evaluate expressions for GDB.
+ 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. */
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "value.h"
+#include "expression.h"
+
+
+/* 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_c_expression (exp);
+ register CORE_ADDR addr;
+ register struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &expr);
+
+ addr = (CORE_ADDR) value_as_long (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_c_1 (expptr, 0, 0);
+ register CORE_ADDR addr;
+ register struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &expr);
+
+ addr = value_as_long (evaluate_expression (expr));
+ do_cleanups (old_chain);
+ return addr;
+}
+
+value
+parse_and_eval (exp)
+ char *exp;
+{
+ struct expression *expr = parse_c_expression (exp);
+ register value 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
+parse_to_comma_and_eval (expp)
+ char **expp;
+{
+ struct expression *expr = parse_c_1 (expp, 0, 1);
+ register value 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 expread.y.
+
+ See expression.h for info on the format of an expression. */
+
+static value evaluate_subexp ();
+static value evaluate_subexp_for_address ();
+static value evaluate_subexp_for_sizeof ();
+static value evaluate_subexp_with_coercion ();
+
+/* return true if 'var' has an address in inferior's memory. */
+static int
+value_has_lval(var)
+ register struct symbol *var;
+{
+ switch (SYMBOL_CLASS(var))
+ {
+ case LOC_STATIC:
+ case LOC_LABEL:
+ case LOC_ARG:
+ case LOC_REF_ARG:
+ case LOC_LOCAL:
+ case LOC_BLOCK:
+ return (1);
+ }
+ return (0);
+}
+
+/* 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). */
+};
+
+value
+evaluate_expression (exp)
+ struct expression *exp;
+{
+ int pc = 0;
+ return evaluate_subexp (0, exp, &pc, EVAL_NORMAL);
+}
+
+/* Evaluate an expression, avoiding all memory references
+ and getting a value whose type alone is correct. */
+
+value
+evaluate_type (exp)
+ struct expression *exp;
+{
+ int pc = 0;
+ return evaluate_subexp (0, exp, &pc, EVAL_AVOID_SIDE_EFFECTS);
+}
+
+static value
+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;
+ register int pc, pc2, oldpos;
+ register value arg1, arg2, arg3;
+ int nargs;
+ value *argvec;
+
+ pc = (*pos)++;
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ case OP_SCOPE:
+ tem = strlen (&exp->elts[pc + 2].string);
+ (*pos) += 3 + ((tem + sizeof (union exp_element))
+ / sizeof (union exp_element));
+ return value_static_field (exp->elts[pc + 1].type,
+ &exp->elts[pc + 2].string, -1);
+
+ case OP_LONG:
+ (*pos) += 3;
+ return value_from_long (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) += 2;
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ struct symbol * sym = exp->elts[pc + 1].symbol;
+ enum lval_type lv;
+
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_CONST:
+ case LOC_LABEL:
+ case LOC_CONST_BYTES:
+ lv = not_lval;
+ case LOC_REGISTER:
+ case LOC_REGPARM:
+ lv = lval_register;
+ default:
+ lv = lval_memory;
+ }
+
+ return value_zero (SYMBOL_TYPE (sym), lv);
+ }
+ else
+ return value_of_variable (exp->elts[pc + 1].symbol);
+
+ case OP_LAST:
+ (*pos) += 2;
+ return access_value_history ((int) exp->elts[pc + 1].longconst);
+
+ case OP_REGISTER:
+ (*pos) += 2;
+ return value_of_register ((int) exp->elts[pc + 1].longconst);
+
+ case OP_INTERNALVAR:
+ (*pos) += 2;
+ return value_of_internalvar (exp->elts[pc + 1].internalvar);
+
+ case OP_STRING:
+ tem = strlen (&exp->elts[pc + 1].string);
+ (*pos) += 2 + ((tem + sizeof (union exp_element))
+ / sizeof (union exp_element));
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_string (&exp->elts[pc + 1].string, tem);
+
+ case TERNOP_COND:
+ /* Skip third and second args to evaluate the first one. */
+ arg1 = evaluate_subexp (0, exp, pos, noside);
+ if (value_zerop (arg1))
+ {
+ evaluate_subexp (0, exp, pos, EVAL_SKIP);
+ return evaluate_subexp (0, exp, pos, noside);
+ }
+ else
+ {
+ arg2 = evaluate_subexp (0, exp, pos, noside);
+ evaluate_subexp (0, 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;
+ int tem2;
+
+ nargs = (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 (0, 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 (0, exp, pos, noside);
+
+ fnptr = (int) value_as_long (arg1);
+ if (fnptr < 128)
+ {
+ struct type *basetype;
+ int i, j;
+ basetype = TYPE_TARGET_TYPE (VALUE_TYPE (arg2));
+ basetype = TYPE_VPTR_BASETYPE (basetype);
+ 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) == fnptr)
+ {
+ value vtbl;
+ value base = value_ind (arg2);
+ struct type *fntype = lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j));
+
+ if (TYPE_VPTR_FIELDNO (basetype) < 0)
+ TYPE_VPTR_FIELDNO (basetype)
+ = fill_in_vptr_fieldno (basetype);
+
+ VALUE_TYPE (base) = basetype;
+ vtbl = value_field (base, TYPE_VPTR_FIELDNO (basetype));
+ VALUE_TYPE (vtbl) = lookup_pointer_type (fntype);
+ VALUE_TYPE (arg1) = builtin_type_int;
+ arg1 = value_subscript (vtbl, arg1);
+ VALUE_TYPE (arg1) = fntype;
+ goto got_it;
+ }
+ }
+ if (i < 0)
+ error ("virtual function at index %d not found", fnptr);
+ }
+ 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 = (int) exp->elts[pc + 1].longconst + 1;
+ /* First, evaluate the structure into arg2 */
+ pc2 = (*pos)++;
+ tem2 = strlen (&exp->elts[pc2 + 1].string);
+ *pos += 2 + (tem2 + sizeof (union exp_element)) / sizeof (union exp_element);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+
+ if (op == STRUCTOP_STRUCT)
+ {
+ arg2 = evaluate_subexp_for_address (exp, pos, noside);
+ }
+ else
+ {
+ arg2 = evaluate_subexp (0, exp, pos, noside);
+ }
+ /* Now, say which argument to start evaluating from */
+ tem = 2;
+ }
+ else
+ {
+ nargs = (int) exp->elts[pc + 1].longconst;
+ tem = 0;
+ }
+ argvec = (value *) alloca (sizeof (value) * (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;
+
+ argvec[1] = arg2;
+ argvec[0] =
+ value_struct_elt (arg2, argvec+1, &exp->elts[pc2 + 1].string,
+ &static_memfuncp,
+ op == STRUCTOP_STRUCT
+ ? "structure" : "structure pointer");
+ 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 (argvec[0], nargs, argvec + 1);
+
+ case STRUCTOP_STRUCT:
+ tem = strlen (&exp->elts[pc + 1].string);
+ (*pos) += 2 + ((tem + sizeof (union exp_element))
+ / sizeof (union exp_element));
+
+ /* Try to convert "foo.bar" into "(&foo)->bar" so we won't copy
+ * the entire contents of a large struct just to extract one
+ * value from it. */
+ if (noside == EVAL_NORMAL && exp->elts[*pos].opcode == OP_VAR_VALUE
+ && value_has_lval(exp->elts[*pos + 1].symbol))
+ arg1 = evaluate_subexp_for_address(exp, pos, noside);
+ else
+ arg1 = evaluate_subexp (0, exp, pos, noside);
+
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ register struct type *type = VALUE_TYPE (arg1);
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ type = TYPE_TARGET_TYPE (type);
+ return value_zero (lookup_struct_elt_type (type,
+ &exp->elts[pc + 1].string),
+ lval_memory);
+ }
+ else
+ return value_struct_elt (arg1, 0, &exp->elts[pc + 1].string, 0,
+ "structure");
+
+ case STRUCTOP_PTR:
+ tem = strlen (&exp->elts[pc + 1].string);
+ (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
+ arg1 = evaluate_subexp (0, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (lookup_struct_elt_type (TYPE_TARGET_TYPE
+ (VALUE_TYPE (arg1)),
+ &exp->elts[pc + 1].string),
+ lval_memory);
+ else
+ return value_struct_elt (arg1, 0, &exp->elts[pc + 1].string, 0,
+ "structure pointer");
+
+ case STRUCTOP_MEMBER:
+ arg1 = evaluate_subexp_for_address (exp, pos, noside);
+ arg2 = evaluate_subexp (0, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ /* Now, convert these values to an address. */
+ if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_PTR
+ || ((TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2)))
+ != TYPE_CODE_MEMBER)
+ && (TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2)))
+ != TYPE_CODE_METHOD)))
+ error ("non-pointer-to-member value used in pointer-to-member construct");
+ arg3 = value_from_long (builtin_type_long,
+ value_as_long (arg1) + value_as_long (arg2));
+ VALUE_TYPE (arg3) =
+ lookup_pointer_type (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))));
+ return value_ind (arg3);
+
+ case STRUCTOP_MPTR:
+ arg1 = evaluate_subexp (0, exp, pos, noside);
+ arg2 = evaluate_subexp (0, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ /* Now, convert these values to an address. */
+ if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_PTR
+ || (TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))) != TYPE_CODE_MEMBER
+ && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))) != TYPE_CODE_METHOD))
+ error ("non-pointer-to-member value used in pointer-to-member construct");
+ arg3 = value_from_long (builtin_type_long,
+ value_as_long (arg1) + value_as_long (arg2));
+ VALUE_TYPE (arg3) =
+ lookup_pointer_type (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))));
+ return value_ind (arg3);
+
+ case BINOP_ASSIGN:
+ arg1 = evaluate_subexp (0, 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, 0);
+ else
+ return value_assign (arg1, arg2);
+
+ case BINOP_ASSIGN_MODIFY:
+ (*pos) += 2;
+ arg1 = evaluate_subexp (0, 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, 0);
+ 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, 0);
+ else
+ return value_sub (arg1, arg2);
+
+ case BINOP_MUL:
+ case BINOP_DIV:
+ case BINOP_REM:
+ case BINOP_LSH:
+ case BINOP_RSH:
+ case BINOP_LOGAND:
+ case BINOP_LOGIOR:
+ case BINOP_LOGXOR:
+ arg1 = evaluate_subexp (0, exp, pos, noside);
+ arg2 = evaluate_subexp (0, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, 0);
+ else
+ if (noside == EVAL_AVOID_SIDE_EFFECTS
+ && op == BINOP_DIV)
+ 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)
+ return value_zero (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)),
+ VALUE_LVAL (arg1));
+
+ if (binop_user_defined_p (op, arg1, arg2))
+ return value_x_binop (arg1, arg2, op, 0);
+ else
+ return value_subscript (arg1, arg2);
+
+ case BINOP_AND:
+ arg1 = evaluate_subexp (0, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ {
+ arg2 = evaluate_subexp (0, exp, pos, noside);
+ goto nosideret;
+ }
+
+ oldpos = *pos;
+ arg2 = evaluate_subexp (0, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ *pos = oldpos;
+
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ arg2 = evaluate_subexp (0, exp, pos, noside);
+ return value_x_binop (arg1, arg2, op, 0);
+ }
+ else
+ {
+ tem = value_zerop (arg1);
+ arg2 = evaluate_subexp (0, exp, pos,
+ (tem ? EVAL_SKIP : noside));
+ return value_from_long (builtin_type_int,
+ (LONGEST) (!tem && !value_zerop (arg2)));
+ }
+
+ case BINOP_OR:
+ arg1 = evaluate_subexp (0, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ {
+ arg2 = evaluate_subexp (0, exp, pos, noside);
+ goto nosideret;
+ }
+
+ oldpos = *pos;
+ arg2 = evaluate_subexp (0, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ *pos = oldpos;
+
+ if (binop_user_defined_p (op, arg1, arg2))
+ {
+ arg2 = evaluate_subexp (0, exp, pos, noside);
+ return value_x_binop (arg1, arg2, op, 0);
+ }
+ else
+ {
+ tem = value_zerop (arg1);
+ arg2 = evaluate_subexp (0, exp, pos,
+ (!tem ? EVAL_SKIP : noside));
+ return value_from_long (builtin_type_int,
+ (LONGEST) (!tem || !value_zerop (arg2)));
+ }
+
+ case BINOP_EQUAL:
+ arg1 = evaluate_subexp (0, 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, 0);
+ }
+ else
+ {
+ tem = value_equal (arg1, arg2);
+ return value_from_long (builtin_type_int, (LONGEST) tem);
+ }
+
+ case BINOP_NOTEQUAL:
+ arg1 = evaluate_subexp (0, 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, 0);
+ }
+ else
+ {
+ tem = value_equal (arg1, arg2);
+ return value_from_long (builtin_type_int, (LONGEST) ! tem);
+ }
+
+ case BINOP_LESS:
+ arg1 = evaluate_subexp (0, 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, 0);
+ }
+ else
+ {
+ tem = value_less (arg1, arg2);
+ return value_from_long (builtin_type_int, (LONGEST) tem);
+ }
+
+ case BINOP_GTR:
+ arg1 = evaluate_subexp (0, 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, 0);
+ }
+ else
+ {
+ tem = value_less (arg2, arg1);
+ return value_from_long (builtin_type_int, (LONGEST) tem);
+ }
+
+ case BINOP_GEQ:
+ arg1 = evaluate_subexp (0, 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, 0);
+ }
+ else
+ {
+ tem = value_less (arg1, arg2);
+ return value_from_long (builtin_type_int, (LONGEST) ! tem);
+ }
+
+ case BINOP_LEQ:
+ arg1 = evaluate_subexp (0, 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, 0);
+ }
+ else
+ {
+ tem = value_less (arg2, arg1);
+ return value_from_long (builtin_type_int, (LONGEST) ! tem);
+ }
+
+ case BINOP_REPEAT:
+ arg1 = evaluate_subexp (0, exp, pos, noside);
+ arg2 = evaluate_subexp (0, 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),
+ (int) value_as_long (arg2));
+ else
+ return value_repeat (arg1, (int) value_as_long (arg2));
+
+ case BINOP_COMMA:
+ evaluate_subexp (0, exp, pos, noside);
+ return evaluate_subexp (0, exp, pos, noside);
+
+ case UNOP_NEG:
+ arg1 = evaluate_subexp (0, 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_LOGNOT:
+ arg1 = evaluate_subexp (0, 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_lognot (arg1);
+
+ case UNOP_ZEROP:
+ arg1 = evaluate_subexp (0, 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_long (builtin_type_int,
+ (LONGEST) value_zerop (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)
+ {
+ char *name = &exp->elts[pc+3].string;
+ int tem = strlen (name);
+ (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
+ }
+ else
+ evaluate_subexp (expect_type, exp, pos, EVAL_SKIP);
+ goto nosideret;
+ }
+
+ if (op == OP_SCOPE)
+ {
+ char *name = &exp->elts[pc+3].string;
+ int tem = strlen (name);
+ struct type *domain = exp->elts[pc+2].type;
+ (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
+ arg1 = value_struct_elt_for_address (domain, expect_type, name);
+ if (arg1)
+ return arg1;
+ error ("no field `%s' in structure", name);
+ }
+ else
+ return evaluate_subexp_for_address (exp, pos, noside);
+
+ case UNOP_SIZEOF:
+ if (noside == EVAL_SKIP)
+ {
+ evaluate_subexp (0, 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 (exp->elts[pc + 1].type,
+ (CORE_ADDR) value_as_long (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_long (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_long (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_long (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_long (builtin_type_char,
+ (LONGEST) 1));
+ value_assign (arg1, arg2);
+ return arg1;
+ }
+
+ case OP_THIS:
+ (*pos) += 1;
+ return value_of_this (1);
+
+ default:
+ error ("internal error: I do not know how to evaluate what you gave me");
+ }
+
+ nosideret:
+ return value_from_long (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
+evaluate_subexp_for_address (exp, pos, noside)
+ register struct expression *exp;
+ register int *pos;
+ enum noside noside;
+{
+ enum exp_opcode op;
+ register int pc;
+
+ pc = (*pos);
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ case UNOP_IND:
+ (*pos)++;
+ return evaluate_subexp (0, exp, pos, noside);
+
+ case UNOP_MEMVAL:
+ (*pos) += 3;
+ return value_cast (lookup_pointer_type (exp->elts[pc + 1].type),
+ evaluate_subexp (0, exp, pos, noside));
+
+ case OP_VAR_VALUE:
+ (*pos) += 3;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ struct type *type =
+ lookup_pointer_type (SYMBOL_TYPE (exp->elts[pc + 1].symbol));
+ enum address_class sym_class =
+ SYMBOL_CLASS (exp->elts[pc + 1].symbol);
+
+ 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 (exp->elts[pc + 1].symbol, (CORE_ADDR) 0);
+
+ default:
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ value x = evaluate_subexp (0, exp, pos, noside);
+ if (VALUE_LVAL (x) == lval_memory)
+ return value_zero (TYPE_POINTER_TYPE (VALUE_TYPE (x)),
+ not_lval);
+ else
+ error ("Attempt to take address of non-lval");
+ }
+ return value_addr (evaluate_subexp (0, 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. */
+
+static value
+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 val;
+
+ pc = (*pos);
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ case OP_VAR_VALUE:
+ if (TYPE_CODE (SYMBOL_TYPE (exp->elts[pc + 1].symbol)) == TYPE_CODE_ARRAY)
+ {
+ (*pos) += 3;
+ val = locate_var_value (exp->elts[pc + 1].symbol, (CORE_ADDR) 0);
+ return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (SYMBOL_TYPE (exp->elts[pc + 1].symbol))),
+ val);
+ }
+ }
+
+ return evaluate_subexp (0, 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
+evaluate_subexp_for_sizeof (exp, pos)
+ register struct expression *exp;
+ register int *pos;
+{
+ enum exp_opcode op;
+ register int pc;
+ value 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 (0, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ return value_from_long (builtin_type_int, (LONGEST)
+ TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (val))));
+
+ case UNOP_MEMVAL:
+ (*pos) += 3;
+ return value_from_long (builtin_type_int,
+ (LONGEST) TYPE_LENGTH (exp->elts[pc + 1].type));
+
+ case OP_VAR_VALUE:
+ (*pos) += 3;
+ return value_from_long (builtin_type_int,
+ (LONGEST) TYPE_LENGTH (SYMBOL_TYPE (exp->elts[pc + 1].symbol)));
+
+ default:
+ val = evaluate_subexp (0, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ return value_from_long (builtin_type_int,
+ (LONGEST) TYPE_LENGTH (VALUE_TYPE (val)));
+ }
+}
diff --git a/gnu/usr.bin/gdb/expprint.c b/gnu/usr.bin/gdb/expprint.c
new file mode 100644
index 0000000..2c63cf8
--- /dev/null
+++ b/gnu/usr.bin/gdb/expprint.c
@@ -0,0 +1,324 @@
+/* Print in infix form a struct expression.
+ Copyright (C) 1986, 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. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "expression.h"
+#include "value.h"
+
+
+/* These codes indicate operator precedences, 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_OR, PREC_AND,
+ PREC_LOGIOR, PREC_LOGAND, PREC_LOGXOR, 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;
+};
+
+static struct op_print op_print_tab[] =
+ {
+ {",", BINOP_COMMA, PREC_COMMA, 0},
+ {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
+ {"||", BINOP_OR, PREC_OR, 0},
+ {"&&", BINOP_AND, PREC_AND, 0},
+ {"|", BINOP_LOGIOR, PREC_LOGIOR, 0},
+ {"&", BINOP_LOGAND, PREC_LOGAND, 0},
+ {"^", BINOP_LOGXOR, PREC_LOGXOR, 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_ZEROP, PREC_PREFIX, 0},
+ {"~", UNOP_LOGNOT, 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},
+ };
+
+static void print_subexp ();
+
+void
+print_expression (exp, stream)
+ struct expression *exp;
+ 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;
+ FILE *stream;
+ enum precedence prec;
+{
+ register int tem;
+ register int pc;
+ int nargs;
+ register char *op_str;
+ int assign_modify = 0;
+ enum exp_opcode opcode;
+ enum precedence myprec;
+ /* Set to 1 for a right-associative operator. */
+ int assoc;
+
+ pc = (*pos)++;
+ opcode = exp->elts[pc].opcode;
+ switch (opcode)
+ {
+ case OP_SCOPE:
+ myprec = PREC_PREFIX;
+ assoc = 0;
+ (*pos) += 2;
+ print_subexp (exp, pos, stream, (int) myprec + assoc);
+ fprintf (stream, " :: ");
+ nargs = strlen (&exp->elts[pc + 2].string);
+ (*pos) += 1 + (nargs + sizeof (union exp_element)) / sizeof (union exp_element);
+
+ fprintf (stream, &exp->elts[pc + 2].string);
+ return;
+
+ case OP_LONG:
+ (*pos) += 3;
+ value_print (value_from_long (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:
+ (*pos) += 2;
+ fprintf (stream, "%s", SYMBOL_NAME (exp->elts[pc + 1].symbol));
+ return;
+
+ case OP_LAST:
+ (*pos) += 2;
+ fprintf (stream, "$%d", (int) exp->elts[pc + 1].longconst);
+ return;
+
+ case OP_REGISTER:
+ (*pos) += 2;
+ fprintf (stream, "$%s", reg_names[exp->elts[pc + 1].longconst]);
+ return;
+
+ case OP_INTERNALVAR:
+ (*pos) += 2;
+ fprintf (stream, "$%s",
+ internalvar_name (exp->elts[pc + 1].internalvar));
+ return;
+
+ case OP_FUNCALL:
+ (*pos) += 2;
+ nargs = exp->elts[pc + 1].longconst;
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fprintf (stream, " (");
+ for (tem = 0; tem < nargs; tem++)
+ {
+ if (tem > 0)
+ fprintf (stream, ", ");
+ print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+ }
+ fprintf (stream, ")");
+ return;
+
+ case OP_STRING:
+ nargs = strlen (&exp->elts[pc + 1].string);
+ (*pos) += 2 + (nargs + sizeof (union exp_element)) / sizeof (union exp_element);
+ fprintf (stream, "\"");
+ for (tem = 0; tem < nargs; tem++)
+ printchar ((&exp->elts[pc + 1].string)[tem], stream, '"');
+ fprintf (stream, "\"");
+ return;
+
+ case TERNOP_COND:
+ if ((int) prec > (int) PREC_COMMA)
+ fprintf (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);
+ fprintf (stream, " ? ");
+ print_subexp (exp, pos, stream, PREC_HYPER);
+ fprintf (stream, " : ");
+ print_subexp (exp, pos, stream, PREC_HYPER);
+ if ((int) prec > (int) PREC_COMMA)
+ fprintf (stream, ")");
+ return;
+
+ case STRUCTOP_STRUCT:
+ tem = strlen (&exp->elts[pc + 1].string);
+ (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fprintf (stream, ".%s", &exp->elts[pc + 1].string);
+ return;
+
+ case STRUCTOP_PTR:
+ tem = strlen (&exp->elts[pc + 1].string);
+ (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fprintf (stream, "->%s", &exp->elts[pc + 1].string);
+ return;
+
+ case BINOP_SUBSCRIPT:
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fprintf (stream, "[");
+ print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+ fprintf (stream, "]");
+ return;
+
+ case UNOP_POSTINCREMENT:
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fprintf (stream, "++");
+ return;
+
+ case UNOP_POSTDECREMENT:
+ print_subexp (exp, pos, stream, PREC_SUFFIX);
+ fprintf (stream, "--");
+ return;
+
+ case UNOP_CAST:
+ (*pos) += 2;
+ if ((int) prec > (int) PREC_PREFIX)
+ fprintf (stream, "(");
+ fprintf (stream, "(");
+ type_print (exp->elts[pc + 1].type, "", stream, 0);
+ fprintf (stream, ") ");
+ print_subexp (exp, pos, stream, PREC_PREFIX);
+ if ((int) prec > (int) PREC_PREFIX)
+ fprintf (stream, ")");
+ return;
+
+ case UNOP_MEMVAL:
+ (*pos) += 2;
+ if ((int) prec > (int) PREC_PREFIX)
+ fprintf (stream, "(");
+ fprintf (stream, "{");
+ type_print (exp->elts[pc + 1].type, "", stream, 0);
+ fprintf (stream, "} ");
+ print_subexp (exp, pos, stream, PREC_PREFIX);
+ if ((int) prec > (int) PREC_PREFIX)
+ fprintf (stream, ")");
+ return;
+
+ case BINOP_ASSIGN_MODIFY:
+ opcode = exp->elts[pc + 1].opcode;
+ (*pos) += 2;
+ myprec = PREC_ASSIGN;
+ assoc = 1;
+ assign_modify = 1;
+ for (tem = 0; tem < sizeof op_print_tab / sizeof op_print_tab[0]; tem++)
+ if (op_print_tab[tem].opcode == opcode)
+ {
+ op_str = op_print_tab[tem].string;
+ break;
+ }
+
+ case OP_THIS:
+ ++(*pos);
+ fprintf (stream, "this");
+ return;
+
+ default:
+ for (tem = 0; tem < sizeof op_print_tab / sizeof op_print_tab[0]; 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 ((int) myprec < (int) prec)
+ fprintf (stream, "(");
+ if ((int) opcode > (int) BINOP_END)
+ {
+ /* Unary prefix operator. */
+ fprintf (stream, "%s", op_str);
+ 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, (int) myprec + assoc);
+ /* Print the operator itself. */
+ if (assign_modify)
+ fprintf (stream, " %s= ", op_str);
+ else if (op_str[0] == ',')
+ fprintf (stream, "%s ", op_str);
+ else
+ fprintf (stream, " %s ", op_str);
+ /* Print right operand.
+ If operator is left-associative,
+ increment precedence for this operand. */
+ print_subexp (exp, pos, stream, (int) myprec + !assoc);
+ }
+ if ((int) myprec < (int) prec)
+ fprintf (stream, ")");
+}
diff --git a/gnu/usr.bin/gdb/expread.y b/gnu/usr.bin/gdb/expread.y
new file mode 100644
index 0000000..96a12c4
--- /dev/null
+++ b/gnu/usr.bin/gdb/expread.y
@@ -0,0 +1,1782 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+/* Parse C expressions for GDB.
+ Copyright (C) 1986, 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. */
+
+/* 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. */
+
+%{
+#ifndef lint
+static char sccsid[] = "@(#)expread.y 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "expression.h"
+
+#include <a.out.h>
+
+static struct expression *expout;
+static int expout_size;
+static int expout_ptr;
+
+static int yylex ();
+static void yyerror ();
+static void write_exp_elt ();
+static void write_exp_elt_opcode ();
+static void write_exp_elt_sym ();
+static void write_exp_elt_longcst ();
+static void write_exp_elt_dblcst ();
+static void write_exp_elt_type ();
+static void write_exp_elt_intern ();
+static void write_exp_string ();
+static void start_arglist ();
+static int end_arglist ();
+static void free_funcalls ();
+static char *copy_name ();
+
+/* If this is nonzero, this block is used as the lexical context
+ for symbol names. */
+
+static struct block *expression_context_block;
+
+/* The innermost context required by the stack and register variables
+ we've encountered so far. */
+struct block *innermost_block;
+
+/* The block in which the most recently discovered symbol was found. */
+struct block *block_found;
+
+/* Number of arguments seen so far in innermost function call. */
+static int arglist_len;
+
+/* 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;
+ };
+
+struct funcall *funcall_chain;
+
+/* This kind of datum is used to represent the name
+ of a symbol token. */
+
+struct stoken
+ {
+ char *ptr;
+ int length;
+ };
+
+/* 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};
+static enum type_pieces *type_stack;
+static int type_stack_depth, type_stack_size;
+
+static void push_type ();
+static enum type_pieces pop_type ();
+
+/* Allow debugging of parsing. */
+#define YYDEBUG 1
+%}
+
+/* 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 exp1 start variable
+%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 <lval> INT CHAR
+%token <ulval> UINT
+%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> NAME TYPENAME BLOCKNAME STRING
+%type <sval> name name_not_typename typename
+
+%token STRUCT UNION ENUM SIZEOF UNSIGNED COLONCOLON
+
+/* Special type cases, put in to allow the parser to distinguish different
+ legal basetypes. */
+%token SIGNED LONG SHORT INT_KEYWORD
+
+%token <lval> LAST REGNAME
+
+%token <ivar> VARIABLE
+
+%token <opcode> ASSIGN_MODIFY
+
+/* C++ */
+%token THIS
+
+%left ','
+%left ABOVE_COMMA
+%right '=' ASSIGN_MODIFY
+%right '?'
+%left OR
+%left AND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOTEQUAL
+%left '<' '>' LEQ GEQ
+%left LSH RSH
+%left '@'
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY INCREMENT DECREMENT
+%right ARROW '.' '[' '('
+%left COLONCOLON
+
+%%
+
+start : exp1
+ ;
+
+/* 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_ZEROP); }
+ ;
+
+exp : '~' exp %prec UNARY
+ { write_exp_elt_opcode (UNOP_LOGNOT); }
+ ;
+
+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 '*' 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 '.' '*' 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); }
+ ;
+
+arglist :
+ ;
+
+arglist : exp
+ { arglist_len = 1; }
+ ;
+
+arglist : arglist ',' exp %prec ABOVE_COMMA
+ { arglist_len++; }
+ ;
+
+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 ($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_LOGAND); }
+ ;
+
+exp : exp '^' exp
+ { write_exp_elt_opcode (BINOP_LOGXOR); }
+ ;
+
+exp : exp '|' exp
+ { write_exp_elt_opcode (BINOP_LOGIOR); }
+ ;
+
+exp : exp AND exp
+ { write_exp_elt_opcode (BINOP_AND); }
+ ;
+
+exp : exp OR exp
+ { write_exp_elt_opcode (BINOP_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);
+ if ($1 == (int) $1 || $1 == (unsigned int) $1)
+ write_exp_elt_type (builtin_type_int);
+ else
+ write_exp_elt_type (BUILTIN_TYPE_LONGEST);
+ write_exp_elt_longcst ((LONGEST) $1);
+ write_exp_elt_opcode (OP_LONG); }
+ ;
+
+exp : UINT
+ {
+ write_exp_elt_opcode (OP_LONG);
+ if ($1 == (unsigned int) $1)
+ write_exp_elt_type (builtin_type_unsigned_int);
+ else
+ write_exp_elt_type (BUILTIN_TYPE_UNSIGNED_LONGEST);
+ 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_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_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
+ { write_exp_elt_opcode (OP_STRING);
+ write_exp_string ($1);
+ write_exp_elt_opcode (OP_STRING); }
+ ;
+
+/* C++. */
+exp : THIS
+ { write_exp_elt_opcode (OP_THIS);
+ write_exp_elt_opcode (OP_THIS); }
+ ;
+
+/* end of C++. */
+
+block : BLOCKNAME
+ {
+ struct symtab *tem = lookup_symtab (copy_name ($1));
+ struct symbol *sym;
+
+ if (tem)
+ $$ = BLOCKVECTOR_BLOCK (BLOCKVECTOR (tem), 1);
+ else
+ {
+ sym = lookup_symbol (copy_name ($1),
+ expression_context_block,
+ VAR_NAMESPACE, 0);
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ $$ = SYMBOL_BLOCK_VALUE (sym);
+ else
+ error ("No file or function \"%s\".",
+ copy_name ($1));
+ }
+ }
+ ;
+
+block : block COLONCOLON name
+ { struct symbol *tem
+ = lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE, 0);
+ 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, 0);
+ if (sym == 0)
+ error ("No symbol \"%s\" in specified context.",
+ copy_name ($3));
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE); }
+ ;
+
+variable: 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);
+ }
+ | COLONCOLON name
+ {
+ char *name = copy_name ($2);
+ struct symbol *sym;
+ int i;
+
+ sym = lookup_symbol (name, 0, VAR_NAMESPACE, 0);
+ if (sym)
+ {
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ break;
+ }
+ for (i = 0; i < misc_function_count; i++)
+ if (!strcmp (misc_function_vector[i].name, name))
+ break;
+
+ if (i < misc_function_count)
+ {
+ enum misc_function_type mft =
+ (enum misc_function_type)
+ misc_function_vector[i].type;
+
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST) misc_function_vector[i].address);
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ if (mft == mf_data || mft == mf_bss)
+ write_exp_elt_type (builtin_type_int);
+ else if (mft == mf_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 (symtab_list == 0
+ && partial_symtab_list == 0)
+ error ("No symbol table is loaded. Use the \"symbol-file\" command.");
+ else
+ error ("No symbol \"%s\" in current context.", name);
+ }
+ ;
+
+variable: name_not_typename
+ { 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);
+ if (sym)
+ {
+ switch (sym->class)
+ {
+ case LOC_REGISTER:
+ case LOC_ARG:
+ case LOC_LOCAL:
+ if (innermost_block == 0 ||
+ contained_in (block_found,
+ innermost_block))
+ innermost_block = block_found;
+ }
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ write_exp_elt_sym (sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ }
+ else if (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);
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ }
+ else
+ {
+ register int i;
+ register char *arg = copy_name ($1);
+
+ for (i = 0; i < misc_function_count; i++)
+ if (!strcmp (misc_function_vector[i].name, arg))
+ break;
+
+ if (i < misc_function_count)
+ {
+ enum misc_function_type mft =
+ (enum misc_function_type)
+ misc_function_vector[i].type;
+
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST) misc_function_vector[i].address);
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_opcode (UNOP_MEMVAL);
+ if (mft == mf_data || mft == mf_bss)
+ write_exp_elt_type (builtin_type_int);
+ else if (mft == mf_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 (symtab_list == 0
+ && partial_symtab_list == 0)
+ error ("No symbol table is loaded. Use the \"symbol-file\" command.");
+ else
+ error ("No symbol \"%s\" in current context.",
+ copy_name ($1));
+ }
+ }
+ ;
+
+
+ptype : typebase
+ | typebase abs_decl
+ {
+ /* This is where the interesting stuff happens. */
+ int done = 0;
+ int array_size;
+ struct type *follow_type = $1;
+
+ 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 = (int) pop_type ();
+ if (array_size != -1)
+ follow_type = create_array_type (follow_type,
+ array_size);
+ else
+ follow_type = lookup_pointer_type (follow_type);
+ break;
+ case tp_function:
+ follow_type = lookup_function_type (follow_type);
+ break;
+ }
+ $$ = follow_type;
+ }
+ ;
+
+abs_decl: '*'
+ { push_type (tp_pointer); $$ = 0; }
+ | '*' abs_decl
+ { push_type (tp_pointer); $$ = $2; }
+ | direct_abs_decl
+ ;
+
+direct_abs_decl: '(' abs_decl ')'
+ { $$ = $2; }
+ | direct_abs_decl array_mod
+ {
+ push_type ((enum type_pieces) $2);
+ push_type (tp_array);
+ }
+ | array_mod
+ {
+ push_type ((enum type_pieces) $1);
+ push_type (tp_array);
+ $$ = 0;
+ }
+ | direct_abs_decl func_mod
+ { push_type (tp_function); }
+ | func_mod
+ { push_type (tp_function); }
+ ;
+
+array_mod: '[' ']'
+ { $$ = -1; }
+ | '[' INT ']'
+ { $$ = $2; }
+ ;
+
+func_mod: '(' ')'
+ { $$ = 0; }
+ ;
+
+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 ($8); }
+ ;
+
+typebase
+ : TYPENAME
+ { $$ = lookup_typename (copy_name ($1),
+ expression_context_block, 0); }
+ | 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; }
+ | SHORT INT_KEYWORD
+ { $$ = builtin_type_short; }
+ | UNSIGNED SHORT INT_KEYWORD
+ { $$ = builtin_type_unsigned_short; }
+ | STRUCT 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 (copy_name ($2)); }
+ | UNSIGNED
+ { $$ = builtin_type_unsigned_int; }
+ | SIGNED typename
+ { $$ = lookup_typename (copy_name ($2),
+ expression_context_block, 0); }
+ | SIGNED
+ { $$ = builtin_type_int; }
+ ;
+
+typename: TYPENAME
+ | INT_KEYWORD
+ {
+ $$.ptr = "int";
+ $$.length = 3;
+ }
+ | LONG
+ {
+ $$.ptr = "long";
+ $$.length = 4;
+ }
+ | SHORT
+ {
+ $$.ptr = "short";
+ $$.length = 5;
+ }
+ ;
+
+nonempty_typelist
+ : type
+ { $$ = (struct type **)xmalloc (sizeof (struct type *) * 2);
+ $$[0] = (struct type *)0;
+ $$[1] = $1;
+ }
+ | nonempty_typelist ',' type
+ { int len = sizeof (struct type *) * ++($<ivec>1[0]);
+ $$ = (struct type **)xrealloc ($1, len);
+ $$[$<ivec>$[0]] = $3;
+ }
+ ;
+
+name : NAME
+ | BLOCKNAME
+ | TYPENAME
+ ;
+
+name_not_typename : NAME
+ | BLOCKNAME
+ ;
+
+%%
+
+/* Begin counting arguments for a function call,
+ saving the data about any containing call. */
+
+static void
+start_arglist ()
+{
+ register struct funcall *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. */
+
+static int
+end_arglist ()
+{
+ register int val = arglist_len;
+ register struct funcall *call = funcall_chain;
+ funcall_chain = call->next;
+ arglist_len = call->arglist_len;
+ free (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 (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 */
+
+static void
+write_exp_elt (expelt)
+ union exp_element expelt;
+{
+ if (expout_ptr >= expout_size)
+ {
+ expout_size *= 2;
+ expout = (struct expression *) xrealloc (expout,
+ sizeof (struct expression)
+ + expout_size * sizeof (union exp_element));
+ }
+ expout->elts[expout_ptr++] = expelt;
+}
+
+static void
+write_exp_elt_opcode (expelt)
+ enum exp_opcode expelt;
+{
+ union exp_element tmp;
+
+ tmp.opcode = expelt;
+
+ write_exp_elt (tmp);
+}
+
+static void
+write_exp_elt_sym (expelt)
+ struct symbol *expelt;
+{
+ union exp_element tmp;
+
+ tmp.symbol = expelt;
+
+ write_exp_elt (tmp);
+}
+
+static void
+write_exp_elt_longcst (expelt)
+ LONGEST expelt;
+{
+ union exp_element tmp;
+
+ tmp.longconst = expelt;
+
+ write_exp_elt (tmp);
+}
+
+static void
+write_exp_elt_dblcst (expelt)
+ double expelt;
+{
+ union exp_element tmp;
+
+ tmp.doubleconst = expelt;
+
+ write_exp_elt (tmp);
+}
+
+static void
+write_exp_elt_type (expelt)
+ struct type *expelt;
+{
+ union exp_element tmp;
+
+ tmp.type = expelt;
+
+ write_exp_elt (tmp);
+}
+
+static 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.
+ Follow it by its length in bytes, as a separate exp_element. */
+
+static void
+write_exp_string (str)
+ struct stoken str;
+{
+ register int len = str.length;
+ register int lenelt
+ = (len + sizeof (union exp_element)) / sizeof (union exp_element);
+
+ expout_ptr += lenelt;
+
+ if (expout_ptr >= expout_size)
+ {
+ expout_size = max (expout_size * 2, expout_ptr + 10);
+ expout = (struct expression *)
+ xrealloc (expout, (sizeof (struct expression)
+ + (expout_size * sizeof (union exp_element))));
+ }
+ bcopy (str.ptr, (char *) &expout->elts[expout_ptr - lenelt], len);
+ ((char *) &expout->elts[expout_ptr - lenelt])[len] = 0;
+ write_exp_elt_longcst ((LONGEST) len);
+}
+
+/* During parsing of a C expression, the pointer to the next character
+ is in this variable. */
+
+static 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. */
+
+static char *namecopy;
+
+/* Current depth in parentheses within the expression. */
+
+static int paren_depth;
+
+/* Nonzero means stop parsing on first comma (if not within parentheses). */
+
+static int comma_terminates;
+
+/* 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 int c;
+ register int base = 10;
+ register int len = olen;
+ char *err_copy;
+ int unsigned_p = 0;
+
+ extern double atof ();
+
+ for (c = 0; c < len; c++)
+ if (p[c] == '.')
+ {
+ /* It's a float since it contains a point. */
+ yylval.dval = atof (p);
+ lexptr += len;
+ return FLOAT;
+ }
+
+ if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2)))
+ {
+ p += 2;
+ base = 16;
+ len -= 2;
+ }
+ else if (*p == '0')
+ base = 8;
+
+ 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 += c - '0';
+ else
+ {
+ if (base == 16 && c >= 'a' && c <= 'f')
+ n += c - 'a' + 10;
+ else if (len == 0 && c == 'l')
+ ;
+ else if (len == 0 && c == 'u')
+ unsigned_p = 1;
+ else if (base == 10 && len != 0 && (c == 'e' || c == 'E'))
+ {
+ /* Scientific notation, where we are unlucky enough not
+ to have a '.' in the string. */
+ yylval.dval = atof (lexptr);
+ lexptr += olen;
+ return FLOAT;
+ }
+ else
+ {
+ err_copy = (char *) alloca (olen + 1);
+ bcopy (lexptr, err_copy, olen);
+ err_copy[olen] = 0;
+ error ("Invalid number \"%s\".", err_copy);
+ }
+ }
+ }
+
+ lexptr = p;
+ if (unsigned_p)
+ {
+ yylval.ulval = n;
+ return UINT;
+ }
+ else
+ {
+ yylval.lval = n;
+ return INT;
+ }
+}
+
+struct token
+{
+ char *operator;
+ int token;
+ enum exp_opcode opcode;
+};
+
+static struct token tokentab3[] =
+ {
+ {">>=", ASSIGN_MODIFY, BINOP_RSH},
+ {"<<=", ASSIGN_MODIFY, BINOP_LSH}
+ };
+
+static 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_LOGIOR},
+ {"&=", ASSIGN_MODIFY, BINOP_LOGAND},
+ {"^=", ASSIGN_MODIFY, BINOP_LOGXOR},
+ {"++", INCREMENT, BINOP_END},
+ {"--", DECREMENT, BINOP_END},
+ {"->", ARROW, BINOP_END},
+ {"&&", AND, BINOP_END},
+ {"||", OR, BINOP_END},
+ {"::", COLONCOLON, BINOP_END},
+ {"<<", LSH, BINOP_END},
+ {">>", RSH, BINOP_END},
+ {"==", EQUAL, BINOP_END},
+ {"!=", NOTEQUAL, BINOP_END},
+ {"<=", LEQ, BINOP_END},
+ {">=", GEQ, BINOP_END}
+ };
+
+/* assign machine-independent names to certain registers
+ * (unless overridden by the REGISTER_NAMES table)
+ */
+struct std_regs {
+ char *name;
+ int regnum;
+} 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
+};
+
+#define NUM_STD_REGS (sizeof std_regs / sizeof std_regs[0])
+
+/* Read one token, getting characters through lexptr. */
+
+static int
+yylex ()
+{
+ register int c;
+ register int namelen;
+ register int i;
+ register char *tokstart;
+
+ retry:
+
+ tokstart = lexptr;
+ /* See if it is a special token of length 3. */
+ for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
+ if (!strncmp (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 (!strncmp (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 '\'':
+ lexptr++;
+ c = *lexptr++;
+ if (c == '\\')
+ c = parse_escape (&lexptr);
+ yylval.lval = c;
+ c = *lexptr++;
+ if (c != '\'')
+ error ("Invalid character constant.");
+ return CHAR;
+
+ 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. */
+
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case '|':
+ case '&':
+ case '^':
+ case '~':
+ case '!':
+ case '@':
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ case '?':
+ case ':':
+ case '=':
+ case '{':
+ case '}':
+ lexptr++;
+ return c;
+
+ case '"':
+ for (namelen = 1; (c = tokstart[namelen]) != '"'; namelen++)
+ if (c == '\\')
+ {
+ c = tokstart[++namelen];
+ if (c >= '0' && c <= '9')
+ {
+ c = tokstart[++namelen];
+ if (c >= '0' && c <= '9')
+ c = tokstart[++namelen];
+ }
+ }
+ yylval.sval.ptr = tokstart + 1;
+ yylval.sval.length = namelen - 1;
+ lexptr += namelen + 1;
+ 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') || c == '.')
+ {
+ /* It's a number. */
+ int got_dot = 0, got_e = 0;
+ register char *p = tokstart;
+ int hex = c == '0' && (p[1] == 'x' || p[1] == 'X');
+ if (hex)
+ p += 2;
+ for (;; ++p)
+ {
+ if (!hex && !got_e && (*p == 'e' || *p == 'E'))
+ got_dot = got_e = 1;
+ else if (!hex && !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 (!got_dot && !got_e && (*p=='l'||*p=='L')){
+ ++p; break;
+ }
+ else if (!got_dot && !got_e && !hex && (*p=='u'||*p=='U')){
+ ++p; break;
+ }
+ else if (*p < '0' || *p > '9'
+ && (!hex || ((*p < 'a' || *p > 'f')
+ && (*p < 'A' || *p > 'F'))))
+ break;
+ }
+ return parse_number (p - tokstart);
+ }
+
+ 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])
+ && !strncmp (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)
+ && !strncmp (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 (!strncmp (tokstart, "unsigned", 8))
+ return UNSIGNED;
+ break;
+ case 6:
+ if (!strncmp (tokstart, "struct", 6))
+ return STRUCT;
+ if (!strncmp (tokstart, "signed", 6))
+ return SIGNED;
+ if (!strncmp (tokstart, "sizeof", 6))
+ return SIZEOF;
+ break;
+ case 5:
+ if (!strncmp (tokstart, "union", 5))
+ return UNION;
+ if (!strncmp (tokstart, "short", 5))
+ return SHORT;
+ break;
+ case 4:
+ if (!strncmp (tokstart, "enum", 4))
+ return ENUM;
+ if (!strncmp (tokstart, "long", 4))
+ return LONG;
+ if (!strncmp (tokstart, "this", 4)
+ && lookup_symbol ("$this", expression_context_block,
+ VAR_NAMESPACE, 0))
+ return THIS;
+ break;
+ case 3:
+ if (!strncmp (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 = (struct internalvar *) 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;
+
+ if (lookup_partial_symtab (tmp))
+ return BLOCKNAME;
+ sym = lookup_symbol (tmp, expression_context_block,
+ VAR_NAMESPACE, 0);
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ return BLOCKNAME;
+ if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1))
+ return TYPENAME;
+ return NAME;
+ }
+}
+
+static void
+yyerror ()
+{
+ error ("Invalid syntax in expression.");
+}
+
+/* Return a null-terminated temporary copy of the name
+ of a string token. */
+
+static char *
+copy_name (token)
+ struct stoken token;
+{
+ bcopy (token.ptr, namecopy, 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_subexp ();
+
+static void
+prefixify_expression (expr)
+ register struct expression *expr;
+{
+ register int len = sizeof (struct expression) +
+ expr->nelts * sizeof (union exp_element);
+ register struct expression *temp;
+ register int inpos = expr->nelts, outpos = 0;
+
+ temp = (struct expression *) alloca (len);
+
+ /* Copy the original expression into temp. */
+ bcopy (expr, temp, 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 < 0)
+ error ("?error in length_of_subexp");
+
+ i = (int) expr->elts[endpos - 1].opcode;
+
+ switch (i)
+ {
+ /* C++ */
+ case OP_SCOPE:
+ oplen = 4 + ((expr->elts[endpos - 2].longconst
+ + sizeof (union exp_element))
+ / sizeof (union exp_element));
+ break;
+
+ case OP_LONG:
+ case OP_DOUBLE:
+ oplen = 4;
+ break;
+
+ case OP_VAR_VALUE:
+ case OP_LAST:
+ case OP_REGISTER:
+ case OP_INTERNALVAR:
+ oplen = 3;
+ break;
+
+ case OP_FUNCALL:
+ oplen = 3;
+ args = 1 + expr->elts[endpos - 2].longconst;
+ break;
+
+ case UNOP_CAST:
+ case UNOP_MEMVAL:
+ oplen = 3;
+ args = 1;
+ break;
+
+ case STRUCTOP_STRUCT:
+ case STRUCTOP_PTR:
+ args = 1;
+ case OP_STRING:
+ oplen = 3 + ((expr->elts[endpos - 2].longconst
+ + sizeof (union exp_element))
+ / sizeof (union exp_element));
+ break;
+
+ case TERNOP_COND:
+ args = 3;
+ 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 = 4 + ((inexpr->elts[inend - 2].longconst
+ + sizeof (union exp_element))
+ / sizeof (union exp_element));
+ break;
+
+ case OP_LONG:
+ case OP_DOUBLE:
+ oplen = 4;
+ break;
+
+ case OP_VAR_VALUE:
+ case OP_LAST:
+ case OP_REGISTER:
+ case OP_INTERNALVAR:
+ oplen = 3;
+ break;
+
+ case OP_FUNCALL:
+ oplen = 3;
+ args = 1 + inexpr->elts[inend - 2].longconst;
+ break;
+
+ case UNOP_CAST:
+ case UNOP_MEMVAL:
+ oplen = 3;
+ args = 1;
+ break;
+
+ case STRUCTOP_STRUCT:
+ case STRUCTOP_PTR:
+ args = 1;
+ case OP_STRING:
+ oplen = 3 + ((inexpr->elts[inend - 2].longconst
+ + sizeof (union exp_element))
+ / sizeof (union exp_element));
+
+ break;
+
+ case TERNOP_COND:
+ args = 3;
+ break;
+
+ case BINOP_ASSIGN_MODIFY:
+ oplen = 3;
+ args = 2;
+ 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;
+ bcopy (&inexpr->elts[inend], &outexpr->elts[outbeg],
+ oplen * sizeof (union exp_element));
+ 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 a C 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_c_1 (stringptr, block, comma)
+ char **stringptr;
+ struct block *block;
+{
+ 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)
+ + expout_size * sizeof (union exp_element));
+ make_cleanup (free_current_contents, &expout);
+ if (yyparse ())
+ yyerror ();
+ discard_cleanups (old_chain);
+ expout->nelts = expout_ptr;
+ expout = (struct expression *)
+ xrealloc (expout,
+ sizeof (struct expression)
+ + expout_ptr * sizeof (union exp_element));
+ prefixify_expression (expout);
+ *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_c_expression (string)
+ char *string;
+{
+ register struct expression *exp;
+ exp = parse_c_1 (&string, 0, 0);
+ if (*string)
+ error ("Junk after end of expression.");
+ return exp;
+}
+
+static void
+push_type (tp)
+ enum type_pieces tp;
+{
+ if (type_stack_depth == type_stack_size)
+ {
+ type_stack_size *= 2;
+ type_stack = (enum type_pieces *)
+ xrealloc (type_stack, type_stack_size * sizeof (enum type_pieces));
+ }
+ type_stack[type_stack_depth++] = tp;
+}
+
+static enum type_pieces
+pop_type ()
+{
+ if (type_stack_depth)
+ return type_stack[--type_stack_depth];
+ return tp_end;
+}
+
+void
+_initialize_expread ()
+{
+ type_stack_size = 80;
+ type_stack_depth = 0;
+ type_stack = (enum type_pieces *)
+ xmalloc (type_stack_size * sizeof (enum type_pieces));
+}
diff --git a/gnu/usr.bin/gdb/expression.h b/gnu/usr.bin/gdb/expression.h
new file mode 100644
index 0000000..5a5e20e
--- /dev/null
+++ b/gnu/usr.bin/gdb/expression.h
@@ -0,0 +1,191 @@
+/* Definitions for expressions stored in reversed prefix form, for GDB.
+ Copyright (C) 1986, 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. */
+
+/* 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
+{
+/* 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_LSH, /* << */
+ BINOP_RSH, /* >> */
+ BINOP_AND, /* && */
+ BINOP_OR, /* || */
+ BINOP_LOGAND, /* & */
+ BINOP_LOGIOR, /* | */
+ BINOP_LOGXOR, /* ^ */
+ 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++. */
+
+ BINOP_END,
+
+ 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. */
+
+/* Operates on three values computed by following subexpressions. */
+ TERNOP_COND, /* ?: */
+
+/* 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 symbol * in the following exp_element,
+ followed by another OP_VAR_VALUE, making three exp_elements. */
+ 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,
+
+/* 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_ZEROP, /* Unary ! */
+ UNOP_LOGNOT, /* 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) */
+
+/* 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 in the next exp_element,
+ (after the string), followed by another STRUCTOP_... code. */
+ 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,
+
+};
+
+union exp_element
+{
+ enum exp_opcode opcode;
+ struct symbol *symbol;
+ LONGEST longconst;
+ double doubleconst;
+ char string;
+ struct type *type;
+ struct internalvar *internalvar;
+};
+
+struct expression
+{
+ int nelts;
+ union exp_element elts[1];
+};
+
+struct expression *parse_c_expression ();
+struct expression *parse_c_1 ();
diff --git a/gnu/usr.bin/gdb/findvar.c b/gnu/usr.bin/gdb/findvar.c
new file mode 100644
index 0000000..0157d10
--- /dev/null
+++ b/gnu/usr.bin/gdb/findvar.c
@@ -0,0 +1,579 @@
+/* Find a variable's value in memory, 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. */
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "value.h"
+
+CORE_ADDR read_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;
+
+#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 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] ?
+ saved_regs.regs[regnum] : 0);
+ }
+#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;
+}
+
+/* Copy the bytes of register REGNUM, relative to the current stack frame,
+ into our memory at MYADDR.
+ The number of bytes copied is REGISTER_RAW_SIZE (REGNUM). */
+
+void
+read_relative_register_raw_bytes (regnum, myaddr)
+ int regnum;
+ char *myaddr;
+{
+ register CORE_ADDR addr;
+
+ if (regnum == FP_REGNUM)
+ {
+ bcopy (&FRAME_FP(selected_frame), myaddr, sizeof (CORE_ADDR));
+ return;
+ }
+
+ addr = find_saved_register (selected_frame, regnum);
+
+ if (addr)
+ {
+ if (regnum == SP_REGNUM)
+ {
+ CORE_ADDR buffer = addr;
+ bcopy (&buffer, myaddr, sizeof (CORE_ADDR));
+ }
+ else
+ read_memory (addr, myaddr, REGISTER_RAW_SIZE (regnum));
+ return;
+ }
+ read_register_bytes (REGISTER_BYTE (regnum),
+ myaddr, REGISTER_RAW_SIZE (regnum));
+}
+
+/* Return a `value' with the contents of register REGNUM
+ in its virtual format, with the type specified by
+ REGISTER_VIRTUAL_TYPE. */
+
+value
+value_of_register (regnum)
+ int regnum;
+{
+ register CORE_ADDR addr;
+ register value val;
+ char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+
+ if (! (have_inferior_p () || have_core_file_p ()))
+ error ("Can't get value of register without inferior or core file");
+
+ addr = find_saved_register (selected_frame, regnum);
+ if (addr)
+ {
+ if (regnum == SP_REGNUM)
+ return value_from_long (builtin_type_int, (LONGEST) addr);
+ read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
+ }
+ else
+ read_register_bytes (REGISTER_BYTE (regnum), raw_buffer,
+ REGISTER_RAW_SIZE (regnum));
+
+ REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer);
+ val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
+ bcopy (virtual_buffer, VALUE_CONTENTS (val), REGISTER_VIRTUAL_SIZE (regnum));
+ VALUE_LVAL (val) = addr ? lval_memory : lval_register;
+ VALUE_ADDRESS (val) = addr ? addr : REGISTER_BYTE (regnum);
+ VALUE_REGNO (val) = regnum;
+ return val;
+}
+
+/* Low level examining and depositing of registers.
+
+ Note that you must call `fetch_registers' once
+ before examining or depositing any registers. */
+
+char registers[REGISTER_BYTES];
+
+/* 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;
+{
+ bcopy (&registers[regbyte], myaddr, len);
+}
+
+/* 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;
+{
+ bcopy (myaddr, &registers[regbyte], len);
+ if (have_inferior_p ())
+ store_inferior_registers (-1);
+}
+
+/* Return the contents of register REGNO,
+ regarding it as an integer. */
+
+CORE_ADDR
+read_register (regno)
+ int regno;
+{
+ /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
+ return *(int *) &registers[REGISTER_BYTE (regno)];
+}
+
+/* Store VALUE in the register number REGNO, regarded as an integer. */
+
+void
+write_register (regno, val)
+ int regno, val;
+{
+ /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
+#if defined(sun4)
+ /* This is a no-op on a Sun 4. */
+ if (regno == 0)
+ return;
+#endif
+
+ *(int *) &registers[REGISTER_BYTE (regno)] = val;
+
+ if (have_inferior_p ())
+ store_inferior_registers (regno);
+}
+
+/* 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;
+{
+ bcopy (val, &registers[REGISTER_BYTE (regno)], REGISTER_RAW_SIZE (regno));
+}
+
+/* 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. */
+
+value
+read_var_value (var, frame)
+ register struct symbol *var;
+ FRAME frame;
+{
+ register value v;
+
+ struct frame_info *fi;
+
+ struct type *type = SYMBOL_TYPE (var);
+ register CORE_ADDR addr = 0;
+ int val = SYMBOL_VALUE (var);
+ 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:
+ case LOC_LABEL:
+ bcopy (&val, VALUE_CONTENTS (v), len);
+ VALUE_LVAL (v) = not_lval;
+ return v;
+
+ case LOC_CONST_BYTES:
+ bcopy (val, VALUE_CONTENTS (v), len);
+ VALUE_LVAL (v) = not_lval;
+ return v;
+
+ case LOC_STATIC:
+ addr = val;
+ break;
+
+/* Nonzero if a struct which is located in a register or a LOC_ARG
+ really contains
+ the address of the struct, not the struct itself. GCC_P is nonzero
+ if the function was compiled with GCC. */
+#if !defined (REG_STRUCT_HAS_ADDR)
+#define REG_STRUCT_HAS_ADDR(gcc_p) 0
+#endif
+
+ case LOC_ARG:
+ fi = get_frame_info (frame);
+ addr = val + FRAME_ARGS_ADDRESS (fi);
+ break;
+
+ case LOC_REF_ARG:
+ fi = get_frame_info (frame);
+ addr = val + FRAME_ARGS_ADDRESS (fi);
+ addr = read_memory_integer (addr, sizeof (CORE_ADDR));
+ break;
+
+ case LOC_LOCAL:
+ fi = get_frame_info (frame);
+ addr = val + FRAME_LOCALS_ADDRESS (fi);
+ break;
+
+ case LOC_TYPEDEF:
+ error ("Cannot look up value of a typedef");
+
+ case LOC_BLOCK:
+ VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var));
+ return v;
+
+ case LOC_REGISTER:
+ case LOC_REGPARM:
+ {
+ struct block *b = get_frame_block (frame);
+
+ v = value_from_register (type, val, frame);
+
+ if (REG_STRUCT_HAS_ADDR(b->gcc_compile_flag)
+ && TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ addr = *(CORE_ADDR *)VALUE_CONTENTS (v);
+ else
+ return v;
+ }
+ }
+
+ read_memory (addr, VALUE_CONTENTS (v), len);
+ VALUE_ADDRESS (v) = addr;
+ return v;
+}
+
+/* Return a value of type TYPE, stored in register REGNUM, in frame
+ FRAME. */
+
+value
+value_from_register (type, regnum, frame)
+ struct type *type;
+ int regnum;
+ FRAME frame;
+{
+ char raw_buffer [MAX_REGISTER_RAW_SIZE];
+ char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+ CORE_ADDR addr;
+ value v = allocate_value (type);
+ int len = TYPE_LENGTH (type);
+ char *value_bytes = 0;
+ int value_bytes_copied = 0;
+ int num_storage_locs;
+
+ 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)
+ {
+ /* 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;
+
+ value_bytes = (char *) alloca (len + MAX_REGISTER_RAW_SIZE);
+
+ /* Copy all of the data out, whereever it may be. */
+
+ for (local_regnum = regnum;
+ value_bytes_copied < len;
+ (value_bytes_copied += REGISTER_RAW_SIZE (local_regnum),
+ ++local_regnum))
+ {
+ int register_index = local_regnum - regnum;
+ addr = find_saved_register (frame, local_regnum);
+ if (addr == 0)
+ {
+ read_register_bytes (REGISTER_BYTE (local_regnum),
+ value_bytes + value_bytes_copied,
+ REGISTER_RAW_SIZE (local_regnum));
+ reg_stor++;
+ }
+ else
+ {
+ read_memory (addr, value_bytes + value_bytes_copied,
+ REGISTER_RAW_SIZE (local_regnum));
+ 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) = find_saved_register (frame, regnum);
+ }
+ else if (reg_stor)
+ {
+ VALUE_LVAL (v) = lval_register;
+ VALUE_ADDRESS (v) = REGISTER_BYTE (regnum);
+ }
+ else
+ fatal ("value_from_register: Value not stored anywhere!");
+
+ /* Any structure stored in more than one register will always be
+ an inegral 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. */
+ bcopy (value_bytes, VALUE_CONTENTS (v), len);
+
+ 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. */
+
+ addr = find_saved_register (frame, regnum);
+ if (addr == 0)
+ {
+ /* Value is really in a register. */
+
+ VALUE_LVAL (v) = lval_register;
+ VALUE_ADDRESS (v) = REGISTER_BYTE (regnum);
+
+ read_register_bytes (REGISTER_BYTE (regnum),
+ raw_buffer, REGISTER_RAW_SIZE (regnum));
+ }
+ else
+ {
+ /* Value was in a register that has been saved in memory. */
+
+ read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
+ VALUE_LVAL (v) = lval_memory;
+ VALUE_ADDRESS (v) = addr;
+ }
+
+ /* Convert the raw contents to virtual contents.
+ (Just copy them if the formats are the same.) */
+
+ REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer);
+
+ if (REGISTER_CONVERTIBLE (regnum))
+ {
+ /* When the raw and virtual formats differ, the virtual format
+ corresponds to a specific data type. If we want that type,
+ copy the data into the value.
+ Otherwise, do a type-conversion. */
+
+ if (type != REGISTER_VIRTUAL_TYPE (regnum))
+ {
+ /* eg a variable of type `float' in a 68881 register
+ with raw type `extended' and virtual type `double'.
+ Fetch it as a `double' and then convert to `float'. */
+ v = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
+ bcopy (virtual_buffer, VALUE_CONTENTS (v), len);
+ v = value_cast (type, v);
+ }
+ else
+ bcopy (virtual_buffer, VALUE_CONTENTS (v), len);
+ }
+ else
+ {
+ /* Raw and virtual formats are the same for this register. */
+
+#ifdef BYTES_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
+
+ bcopy (virtual_buffer + VALUE_OFFSET (v),
+ VALUE_CONTENTS (v), len);
+ }
+
+ return v;
+}
+
+/* Given a struct symbol for a variable,
+ and a stack frame id,
+ return a (pointer to a) struct value containing the variable's address. */
+
+value
+locate_var_value (var, frame)
+ register struct symbol *var;
+ FRAME frame;
+{
+ register CORE_ADDR addr = 0;
+ int val = SYMBOL_VALUE (var);
+ struct frame_info *fi;
+ struct type *type = SYMBOL_TYPE (var);
+ struct type *result_type;
+
+ if (frame == 0) frame = selected_frame;
+
+ switch (SYMBOL_CLASS (var))
+ {
+ case LOC_CONST:
+ case LOC_CONST_BYTES:
+ error ("Address requested for identifier \"%s\" which is a constant.",
+ SYMBOL_NAME (var));
+
+ case LOC_REGISTER:
+ case LOC_REGPARM:
+ addr = find_saved_register (frame, val);
+ if (addr != 0)
+ {
+ int len = TYPE_LENGTH (type);
+#ifdef BYTES_BIG_ENDIAN
+ if (len < REGISTER_RAW_SIZE (val))
+ /* Big-endian, and we want less than full size. */
+ addr += REGISTER_RAW_SIZE (val) - len;
+#endif
+ break;
+ }
+ error ("Address requested for identifier \"%s\" which is in a register.",
+ SYMBOL_NAME (var));
+
+ case LOC_STATIC:
+ case LOC_LABEL:
+ addr = val;
+ break;
+
+ case LOC_ARG:
+ fi = get_frame_info (frame);
+ addr = val + FRAME_ARGS_ADDRESS (fi);
+ break;
+
+ case LOC_REF_ARG:
+ fi = get_frame_info (frame);
+ addr = val + FRAME_ARGS_ADDRESS (fi);
+ addr = read_memory_integer (addr, sizeof (CORE_ADDR));
+ break;
+
+ case LOC_LOCAL:
+ fi = get_frame_info (frame);
+ addr = val + FRAME_LOCALS_ADDRESS (fi);
+ break;
+
+ case LOC_TYPEDEF:
+ error ("Address requested for identifier \"%s\" which is a typedef.",
+ SYMBOL_NAME (var));
+
+ case LOC_BLOCK:
+ addr = BLOCK_START (SYMBOL_BLOCK_VALUE (var));
+ break;
+ }
+
+ /* Address of an array is of the type of address of it's elements. */
+ result_type =
+ lookup_pointer_type (TYPE_CODE (type) == TYPE_CODE_ARRAY ?
+ TYPE_TARGET_TYPE (type) : type);
+
+ return value_cast (result_type,
+ value_from_long (builtin_type_long, (LONGEST) addr));
+}
+
diff --git a/gnu/usr.bin/gdb/frame.h b/gnu/usr.bin/gdb/frame.h
new file mode 100644
index 0000000..322ddba
--- /dev/null
+++ b/gnu/usr.bin/gdb/frame.h
@@ -0,0 +1,115 @@
+/* Definitions for dealing with stack frames, for GDB, the GNU debugger.
+ Copyright (C) 1986, 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. */
+
+/* Note that frame.h requires param.h! */
+
+/*
+ * FRAME is the type of the identifier of a specific stack frame. It
+ * is a pointer to the frame cache item corresponding to this frame.
+ * Please note that frame id's are *not* constant over calls to the
+ * inferior. Use frame addresses, which are.
+ *
+ * FRAME_ADDR is the type of the address of a specific frame. I
+ * cannot imagine a case in which this would not be CORE_ADDR, so
+ * maybe it's silly to give it it's own type. Life's rough.
+ *
+ * FRAME_FP is a macro which converts from a frame identifier into a
+ * frame_address.
+ *
+ * FRAME_INFO_ID is a macro which "converts" from a frame info pointer
+ * to a frame id. This is here in case I or someone else decides to
+ * change the FRAME type again.
+ *
+ * This file and blockframe.c are the only places which are allowed to
+ * use the equivalence between FRAME and struct frame_info *. EXCEPTION:
+ * value.h uses CORE_ADDR instead of FRAME_ADDR because the compiler
+ * will accept that in the absense of this file.
+ */
+typedef struct frame_info *FRAME;
+typedef CORE_ADDR FRAME_ADDR;
+#define FRAME_FP(fr) ((fr)->frame)
+#define FRAME_INFO_ID(f) (f)
+
+/*
+ * Caching structure for stack frames. This is also the structure
+ * used for extended info about stack frames. May add more to this
+ * structure as it becomes necessary.
+ *
+ * Note that the first entry in the cache will always refer to the
+ * innermost executing frame. This value should be set (is it?
+ * Check) in something like normal_stop.
+ */
+struct frame_info
+ {
+ /* Nominal address of the frame described. */
+ 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;
+ /* The frame called by the frame we are describing, or 0.
+ This may be set even if there isn't a frame called by the one
+ we are describing (.->next == 0); in that case it is simply the
+ bottom of this frame */
+ FRAME_ADDR next_frame;
+ /* Anything extra for this structure that may have been defined
+ in the machine depedent files. */
+#ifdef EXTRA_FRAME_INFO
+ EXTRA_FRAME_INFO
+#endif
+ /* Pointers to the next and previous frame_info's in this stack. */
+ 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. */
+ CORE_ADDR regs[NUM_REGS];
+ };
+
+/* 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;
+
+extern struct frame_info *get_frame_info ();
+extern struct frame_info *get_prev_frame_info ();
+
+extern FRAME create_new_frame ();
+
+extern void get_frame_saved_regs ();
+
+extern FRAME get_prev_frame ();
+extern FRAME get_current_frame ();
+extern FRAME get_next_frame ();
+
+extern struct block *get_frame_block ();
+extern struct block *get_current_block ();
+extern struct block *get_selected_block ();
+extern struct symbol *get_frame_function ();
+extern struct symbol *get_pc_function ();
+
+/* In stack.c */
+extern FRAME find_relative_frame ();
+
+/* Generic pointer value indicating "I don't know." */
+#define Frame_unknown (CORE_ADDR)-1
diff --git a/gnu/usr.bin/gdb/gdb.1 b/gnu/usr.bin/gdb/gdb.1
new file mode 100644
index 0000000..57d744b
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb.1
@@ -0,0 +1,3 @@
+.\" %W% (Berkeley) %G%
+.\"
+.\" placeholder, until we can produce the manual page
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..2fac3db
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/Makefile
@@ -0,0 +1,72 @@
+PROG = gdb
+BINDIR= /usr/bin
+SRCS = main.c blockframe.c breakpoint.c findvar.c stack.c thread.c \
+ source.c values.c eval.c valops.c valarith.c valprint.c printcmd.c \
+ symtab.c symfile.c symmisc.c infcmd.c infrun.c command.c utils.c \
+ expprint.c environ.c gdbtypes.c copying.c i386-tdep.c i386-pinsn.c \
+ freebsd-solib.c ser-unix.c exec.c fork-child.c infptrace.c inftarg.c \
+ corelow.c coredep.c freebsd-nat.c remote.c dcache.c remote-utils.c \
+ mem-break.c target.c putenv.c parse.c language.c buildsym.c \
+ objfiles.c minsyms.c maint.c demangle.c dbxread.c coffread.c \
+ elfread.c dwarfread.c mipsread.c stabsread.c core.c c-lang.c \
+ ch-lang.c m2-lang.c complaints.c typeprint.c c-typeprint.c \
+ ch-typeprint.c m2-typeprint.c c-valprint.c cp-valprint.c ch-valprint.c \
+ m2-valprint.c nlmread.c serial.c inflow.c regex.c init.c \
+ c-exp.tab.c ch-exp.tab.c m2-exp.tab.c version.c i386-dis.c dis-buf.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/usr/include/readline -I$(.CURDIR)/../bfd
+DPADD+= $(LIBREADLINE) $(LIBTERM)
+LDADD+= -lreadline -ltermcap
+
+.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/ansidecl.h b/gnu/usr.bin/gdb/gdb/ansidecl.h
new file mode 100644
index 0000000..fdc4072
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ansidecl.h
@@ -0,0 +1,139 @@
+/* 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 *'
+
+ 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
+
+#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..018e6dd
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/aout64.h
@@ -0,0 +1,431 @@
+/* `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. */
+
+/* This indicates a demand-paged executable with the header in the text.
+ As far as I know it is only used by 386BSD and/or BSDI. */
+#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 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
+
+#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
+
+/* 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 */\
+ PAGE_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 {N,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. But if it doesn't (I
+ think maybe this happens on BSDI and/or 386BSD), then add it. */
+
+#ifndef N_DATOFF
+#define N_DATOFF(x) \
+ (N_MAGIC(x) == OMAGIC ? N_TXTOFF(x) + N_TXTSIZE(x) : \
+ PAGE_SIZE + ((N_TXTOFF(x) + N_TXTSIZE(x) - 1) & ~(PAGE_SIZE - 1)))
+#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
+
+/* 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 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 (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 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
+
+/* 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,
+
+
+ /* 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..cca636d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/aout/ar.h
@@ -0,0 +1,32 @@
+/* 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__
+
+#define ARMAG "!<arch>\n" /* For COFF and a.out archives */
+#define ARMAGB "!<bout>\n" /* For b.out archives */
+#define SARMAG 8
+#define ARFMAG "`\n"
+
+/* 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/ranlib.h b/gnu/usr.bin/gdb/gdb/aout/ranlib.h
new file mode 100644
index 0000000..53e35ce
--- /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/stab.def b/gnu/usr.bin/gdb/gdb/aout/stab.def
new file mode 100644
index 0000000..9d1da7d
--- /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 |
+ | 09 |EXT | 0B | 0D | 0F |
+
+ | 10 | 12 COMM | 14 SETA | 16 SETT |
+ | 11 | 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/blockframe.c b/gnu/usr.bin/gdb/gdb/blockframe.c
new file mode 100644
index 0000000..c7b3fdc
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/blockframe.c
@@ -0,0 +1,821 @@
+/* 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 */
+
+/* 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 */
+}
+
+/* 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.
+ 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. */
+
+#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 it's value
+ (see tm-sparc.h). We want the pc saved in the inferior frame. */
+ INIT_FRAME_PC(fromleaf, prev);
+
+ 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)
+ 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;
+ }
+}
+
+#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..69694c0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/breakpoint.c
@@ -0,0 +1,3301 @@
+/* Everything about breakpoints, for GDB.
+ Copyright 1986, 1987, 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 <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 "target.h"
+#include "language.h"
+#include <string.h>
+#include "demangle.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 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));
+
+
+extern int addressprint; /* Print machine addresses? */
+extern int demangle; /* Print de-mangled symbol names? */
+
+/* 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)
+
+/* Chain of all breakpoints defined. */
+
+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));
+}
+
+/* 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;
+
+/* Flag indicating extra verbosity for xgdb. */
+extern int xgdb_verbose;
+
+/* *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 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;
+ 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->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->enable != disabled
+ && ! b->inserted
+ && ! b->duplicate)
+ {
+ 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)
+ {
+ fprintf (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
+ {
+ fprintf (stderr, "Cannot insert breakpoint %d:\n", b->number);
+#ifdef ONE_PROCESS_WRITETEXT
+ fprintf (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;
+ }
+ if (disabled_breaks)
+ printf_filtered ("\n");
+ return val;
+}
+
+int
+remove_breakpoints ()
+{
+ register struct breakpoint *b;
+ int val;
+
+#ifdef BREAKPOINT_DEBUG
+ printf ("Removing breakpoints.\n");
+#endif /* BREAKPOINT_DEBUG */
+
+ ALL_BREAKPOINTS (b)
+ if (b->type != bp_watchpoint && b->inserted)
+ {
+ val = target_remove_breakpoint(b->address, b->shadow_contents);
+ if (val)
+ return val;
+ b->inserted = 0;
+#ifdef BREAKPOINT_DEBUG
+ printf ("Removed breakpoint at %s",
+ local_hex_string((unsigned long) b->address));
+ printf (", shadow %s",
+ local_hex_string((unsigned long) b->shadow_contents[0]));
+ printf (", %s.\n",
+ local_hex_string((unsigned long) b->shadow_contents[1]));
+#endif /* BREAKPOINT_DEBUG */
+ }
+
+ 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);
+ }
+}
+
+/* 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;
+}
+
+/* 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_watchpoint))
+ return 0;
+
+ if (bs->breakpoint_at->type == bp_breakpoint)
+ {
+ /* I think the user probably only wants to see one breakpoint
+ number, not all of them. */
+ printf_filtered ("\nBreakpoint %d, ", bs->breakpoint_at->number);
+ return 0;
+ }
+
+ if (bs->old_val != NULL)
+ {
+ printf_filtered ("\nWatchpoint %d, ", bs->breakpoint_at->number);
+ print_expression (bs->breakpoint_at->exp, stdout);
+ printf_filtered ("\nOld value = ");
+ value_print (bs->old_val, stdout, 0, Val_pretty_default);
+ printf_filtered ("\nNew value = ");
+ value_print (bs->breakpoint_at->val, stdout, 0,
+ Val_pretty_default);
+ printf_filtered ("\n");
+ value_free (bs->old_val);
+ bs->old_val = NULL;
+ return 0;
+ }
+ /* 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;
+{
+ return !value_true (evaluate_expression ((struct expression *)exp));
+}
+
+/* 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;
+}
+
+/* Return the frame which we can use to evaluate the expression
+ whose valid block is valid_block, or NULL if not in scope.
+
+ This whole concept is probably not the way to do things (it is incredibly
+ slow being the main reason, not to mention fragile (e.g. the sparc
+ frame pointer being fetched as 0 bug causes it to stop)). Instead,
+ introduce a version of "struct frame" which survives over calls to the
+ inferior, but which is better than FRAME_ADDR in the sense that it lets
+ us evaluate expressions relative to that frame (on some machines, it
+ can just be a FRAME_ADDR). Save one of those instead of (or in addition
+ to) the exp_valid_block, and then use it to evaluate the watchpoint
+ expression, with no need to do all this backtracing every time.
+
+ Or better yet, what if it just copied the struct frame and its next
+ frame? Off the top of my head, I would think that would work
+ because things like (a29k) rsize and msize, or (sparc) bottom just
+ depend on the frame, and aren't going to be different just because
+ the inferior has done something. Trying to recalculate them
+ strikes me as a lot of work, possibly even impossible. Saving the
+ next frame is needed at least on a29k, where get_saved_register
+ uses fi->next->saved_msp. For figuring out whether that frame is
+ still on the stack, I guess this needs to be machine-specific (e.g.
+ a29k) but I think
+
+ read_fp () INNER_THAN watchpoint_frame->frame
+
+ would generally work.
+
+ Of course the scope of the expression could be less than a whole
+ function; perhaps if the innermost frame is the one which the
+ watchpoint is relative to (another machine-specific thing, usually
+
+ FRAMELESS_FUNCTION_INVOCATION (get_current_frame(), fromleaf)
+ read_fp () == wp_frame->frame
+ && !fromleaf
+
+ ), *then* it could do a
+
+ contained_in (get_current_block (), wp->exp_valid_block).
+
+ */
+
+FRAME
+within_scope (valid_block)
+ struct block *valid_block;
+{
+ FRAME fr = get_current_frame ();
+ struct frame_info *fi = get_frame_info (fr);
+ CORE_ADDR func_start;
+
+ /* If caller_pc_valid is true, we are stepping through
+ a function prologue, which is bounded by callee_func_start
+ (inclusive) and callee_prologue_end (exclusive).
+ caller_pc is the pc of the caller.
+
+ Yes, this is hairy. */
+ static int caller_pc_valid = 0;
+ static CORE_ADDR caller_pc;
+ static CORE_ADDR callee_func_start;
+ static CORE_ADDR callee_prologue_end;
+
+ find_pc_partial_function (fi->pc, (PTR)NULL, &func_start, (CORE_ADDR *)NULL);
+ func_start += FUNCTION_START_OFFSET;
+ if (fi->pc == func_start)
+ {
+ /* We just called a function. The only other case I
+ can think of where the pc would equal the pc of the
+ start of a function is a frameless function (i.e.
+ no prologue) where we branch back to the start
+ of the function. In that case, SKIP_PROLOGUE won't
+ find one, and we'll clear caller_pc_valid a few lines
+ down. */
+ caller_pc_valid = 1;
+ caller_pc = SAVED_PC_AFTER_CALL (fr);
+ callee_func_start = func_start;
+ SKIP_PROLOGUE (func_start);
+ callee_prologue_end = func_start;
+ }
+ if (caller_pc_valid)
+ {
+ if (fi->pc < callee_func_start
+ || fi->pc >= callee_prologue_end)
+ caller_pc_valid = 0;
+ }
+
+ if (contained_in (block_for_pc (caller_pc_valid
+ ? caller_pc
+ : fi->pc),
+ valid_block))
+ {
+ return fr;
+ }
+ fr = get_prev_frame (fr);
+
+ /* If any active frame is in the exp_valid_block, then it's
+ OK. Note that this might not be the same invocation of
+ the exp_valid_block that we were watching a little while
+ ago, or the same one as when the watchpoint was set (e.g.
+ we are watching a local variable in a recursive function.
+ When we return from a recursive invocation, then we are
+ suddenly watching a different instance of the variable).
+
+ At least for now I am going to consider this a feature. */
+ for (; fr != NULL; fr = get_prev_frame (fr))
+ {
+ fi = get_frame_info (fr);
+ if (contained_in (block_for_pc (fi->pc),
+ valid_block))
+ {
+ return fr;
+ }
+ }
+ return NULL;
+}
+
+/* Possible return values for watchpoint_check (this can't be an enum
+ because of check_errors). */
+/* The watchpoint has been disabled. */
+#define WP_DISABLED 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;
+ FRAME fr;
+
+ int within_current_scope;
+ if (bs->breakpoint_at->exp_valid_block == NULL)
+ within_current_scope = 1;
+ else
+ {
+ fr = within_scope (bs->breakpoint_at->exp_valid_block);
+ 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 mark = value_mark ();
+ value new_val = evaluate_expression (bs->breakpoint_at->exp);
+ if (!value_equal (bs->breakpoint_at->val, new_val))
+ {
+ release_value (new_val);
+ value_free_to_mark (mark);
+ bs->old_val = bs->breakpoint_at->val;
+ bs->breakpoint_at->val = new_val;
+ /* We will stop here */
+ return WP_VALUE_CHANGED;
+ }
+ else
+ {
+ /* Nothing changed, don't do anything. */
+ value_free_to_mark (mark);
+ /* We won't stop here */
+ 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). */
+ bs->breakpoint_at->enable = disabled;
+ printf_filtered ("\
+Watchpoint %d disabled because the program has left the block in\n\
+which its expression is valid.\n", bs->breakpoint_at->number);
+ return WP_DISABLED;
+ }
+}
+
+/* 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;
+
+ /* 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->address != bp_addr)
+ continue;
+
+ if (b->type != bp_watchpoint && not_a_breakpoint)
+ continue;
+
+ /* Come here if it's a watchpoint, or if the break address matches */
+
+ bs = bpstat_alloc (b, bs); /* Alloc a bpstat to explain stop */
+
+ bs->stop = 1;
+ bs->print = 1;
+
+ if (b->type == bp_watchpoint)
+ {
+ static char message1[] =
+ "Error evaluating expression for watchpoint %d\n";
+ char message[sizeof (message1) + 30 /* slop */];
+ sprintf (message, message1, b->number);
+ switch (catch_errors (watchpoint_check, (char *) bs, message,
+ RETURN_MASK_ALL))
+ {
+ case WP_DISABLED:
+ /* 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. */
+ b->enable = disabled;
+ printf_filtered ("Watchpoint %d disabled.\n", b->number);
+ /* We've already printed what needs to be printed. */
+ bs->print_it = print_it_done;
+ /* Stop. */
+ 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. */
+ 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,
+
+ /* 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
+/* "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. */
+ 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 */
+
+/*no_effect*/ {keep_c, stop_s, stop_n, single, setlr , clrlr , clrlrs},
+/*wp_silent*/ {stop_s, stop_s, stop_n, stop_s, stop_s, stop_s, stop_s},
+/*wp_noisy*/ {stop_n, stop_n, stop_n, stop_n, stop_n, stop_n, stop_n},
+/*bp_nostop*/ {single, stop_s, stop_n, single, setlr , clrlrs, clrlrs},
+/*bp_silent*/ {stop_s, stop_s, stop_n, stop_s, stop_s, stop_s, stop_s},
+/*bp_noisy*/ {stop_n, stop_n, stop_n, stop_n, stop_n, stop_n, stop_n},
+/*long_jump*/ {setlr , stop_s, stop_n, setlr , err , err , err },
+/*long_resume*/ {clrlr , stop_s, stop_n, clrlrs, err , err , err }
+ };
+#undef keep_c
+#undef stop_s
+#undef stop_n
+#undef single
+#undef setlr
+#undef clrlr
+#undef clrlrs
+#undef err
+ enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING;
+ struct bpstat_what retval;
+
+ retval.call_dummy = 0;
+ retval.step_resume = 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_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:
+ 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 0
+ /* Need to temporarily disable this until we can fix the bug
+ with nexting over a breakpoint with ->stop clear causing
+ an infinite loop. For now, treat the breakpoint as having
+ been hit even if the frame is wrong. */
+ if (bs->stop)
+ {
+#endif
+ retval.step_resume = 1;
+ /* We don't handle this via the main_action. */
+ bs_class = no_effect;
+#if 0
+ }
+ else
+ /* It is for the wrong frame. */
+ bs_class = bp_nostop;
+#endif
+ 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", "until", "finish", "watchpoint",
+ "longjmp", "longjmp resume", "step resume",
+ "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_watchpoint)
+ continue;
+
+ if (!found_a_breakpoint++)
+ printf_filtered ("Num Type Disp Enb %sWhat\n",
+ addressprint ? "Address " : "");
+
+ printf_filtered ("%-3d %-14s %-4s %-3c ",
+ b->number,
+ bptypes[(int)b->type],
+ bpdisps[(int)b->disposition],
+ bpenables[(int)b->enable]);
+ strcpy (wrap_indent, " ");
+ if (addressprint)
+ strcat (wrap_indent, " ");
+ switch (b->type)
+ {
+ case bp_watchpoint:
+ print_expression (b->exp, stdout);
+ break;
+
+ case bp_breakpoint:
+ case bp_until:
+ case bp_finish:
+ case bp_longjmp:
+ case bp_longjmp_resume:
+ case bp_step_resume:
+ case bp_call_dummy:
+ if (addressprint)
+ printf_filtered ("%s ", local_hex_string_custom ((unsigned long) b->address, "08l"));
+
+ last_addr = b->address;
+ if (b->source_file)
+ {
+ sym = find_pc_function (b->address);
+ if (sym)
+ {
+ fputs_filtered ("in ", stdout);
+ fputs_filtered (SYMBOL_SOURCE_NAME (sym), stdout);
+ wrap_here (wrap_indent);
+ fputs_filtered (" at ", stdout);
+ }
+ fputs_filtered (b->source_file, stdout);
+ printf_filtered (":%d", b->line_number);
+ }
+ else
+ print_address_symbolic (b->address, stdout, demangle, " ");
+ break;
+ }
+
+ printf_filtered ("\n");
+
+ if (b->frame)
+ printf_filtered ("\tstop only in stack frame at %s\n",
+ local_hex_string((unsigned long) b->frame));
+ if (b->cond)
+ {
+ printf_filtered ("\tstop only if ");
+ print_expression (b->cond, stdout);
+ printf_filtered ("\n");
+ }
+ if (b->ignore_count)
+ printf_filtered ("\tignore next %d hits\n", b->ignore_count);
+ if ((l = b->commands))
+ while (l)
+ {
+ fputs_filtered ("\t", stdout);
+ fputs_filtered (l->line, stdout);
+ fputs_filtered ("\n", 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);
+}
+
+/* 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 ("Note: breakpoint%s ", (others > 1) ? "s" : "");
+ ALL_BREAKPOINTS (b)
+ if (b->address == pc)
+ {
+ others--;
+ printf ("%d%s%s ",
+ b->number,
+ (b->enable == disabled) ? " (disabled)" : "",
+ (others > 1) ? "," : ((others == 1) ? " and" : ""));
+ }
+ printf ("also set at pc %s.\n", local_hex_string((unsigned long) pc));
+ }
+}
+
+/* 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);
+
+ 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);
+ }
+}
+
+/* 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;
+{
+ switch (b->type)
+ {
+ case bp_watchpoint:
+ printf_filtered ("Watchpoint %d: ", b->number);
+ print_expression (b->exp, stdout);
+ break;
+ case bp_breakpoint:
+ printf_filtered ("Breakpoint %d at %s", b->number,
+ local_hex_string((unsigned long) b->address));
+ if (b->source_file)
+ printf_filtered (": file %s, line %d.",
+ b->source_file, b->line_number);
+ break;
+ case bp_until:
+ case bp_finish:
+ case bp_longjmp:
+ case bp_longjmp_resume:
+ case bp_step_resume:
+ break;
+ }
+ 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)
+ and make it temporary if TEMPFLAG is nonzero. */
+
+static void
+break_command_1 (arg, tempflag, from_tty)
+ char *arg;
+ int tempflag, from_tty;
+{
+ 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;
+
+ 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.");
+ }
+ }
+
+ /* 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 = 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 ("Multiple breakpoints were set.\n");
+ printf ("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;
+ }
+}
+
+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, 1, from_tty);
+}
+
+/* ARGSUSED */
+static void
+watch_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct breakpoint *b;
+ struct symtab_and_line sal;
+ struct expression *exp;
+ struct block *exp_valid_block;
+ struct value *val;
+
+ sal.pc = 0;
+ sal.symtab = NULL;
+ sal.line = 0;
+
+ /* Parse arguments. */
+ innermost_block = NULL;
+ exp = parse_expression (arg);
+ exp_valid_block = innermost_block;
+ val = evaluate_expression (exp);
+ release_value (val);
+ if (VALUE_LAZY (val))
+ value_fetch_lazy (val);
+
+ /* Now set up the breakpoint. */
+ b = set_raw_breakpoint (sal);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->type = bp_watchpoint;
+ b->disposition = donttouch;
+ b->exp = exp;
+ b->exp_valid_block = exp_valid_block;
+ b->val = val;
+ b->cond = 0;
+ b->cond_string = NULL;
+ b->exp_string = savestring (arg, strlen (arg));
+ mention (b);
+}
+
+/*
+ * 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, -1, 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 ("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 ("Multiple breakpoints were set.\n");
+ printf ("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
+ && (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 ("Deleted breakpoint%s ", found->next ? "s" : "");
+ while (found)
+ {
+ if (from_tty) printf ("%d ", found->number);
+ b1 = found->next;
+ delete_breakpoint (found);
+ found = b1;
+ }
+ if (from_tty) putchar ('\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)
+ target_remove_breakpoint(bpt->address, bpt->shadow_contents);
+
+ 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)
+ {
+ 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)
+ {
+ fprintf (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);
+
+ if (xgdb_verbose && bpt->type == bp_breakpoint)
+ printf ("breakpoint #%d deleted\n", bpt->number);
+
+ /* 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 */
+ int i;
+ struct symtabs_and_lines sals;
+ char *s;
+ enum enable save_enable;
+
+ switch (b->type)
+ {
+ case bp_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);
+ }
+ b->enable = save_enable; /* Restore it, this worked. */
+ }
+ free ((PTR)sals.sals);
+ break;
+
+ case bp_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;
+ 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);
+ 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_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);
+ 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");
+}
+
+/* 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)
+ {
+ function (b);
+ goto win;
+ }
+ printf ("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;
+
+ bpt->enable = enabled;
+
+ if (xgdb_verbose && bpt->type == bp_breakpoint)
+ printf ("breakpoint #%d enabled\n", bpt->number);
+
+ check_duplicates (bpt->address);
+ if (bpt->type == bp_watchpoint)
+ {
+ if (bpt->exp_valid_block != NULL)
+ {
+ FRAME fr = within_scope (bpt->exp_valid_block);
+ 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);
+
+ bpt->val = evaluate_expression (bpt->exp);
+ release_value (bpt->val);
+ if (VALUE_LAZY (bpt->val))
+ value_fetch_lazy (bpt->val);
+
+ if (save_selected_frame_level >= 0)
+ select_frame (save_selected_frame, save_selected_frame_level);
+ }
+}
+
+/* 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_watchpoint:
+ enable_breakpoint (bpt);
+ default:
+ continue;
+ }
+ else
+ map_breakpoint_numbers (args, enable_breakpoint);
+}
+
+static void
+disable_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ bpt->enable = disabled;
+
+ if (xgdb_verbose && bpt->type == bp_breakpoint)
+ printf_filtered ("breakpoint #%d disabled\n", bpt->number);
+
+ 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_watchpoint:
+ disable_breakpoint (bpt);
+ default:
+ continue;
+ }
+ else
+ map_breakpoint_numbers (args, disable_breakpoint);
+}
+
+static void
+enable_once_breakpoint (bpt)
+ struct breakpoint *bpt;
+{
+ bpt->enable = enabled;
+ bpt->disposition = disable;
+
+ check_duplicates (bpt->address);
+}
+
+/* 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);
+}
+
+/* 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.");
+
+ 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\
+N is an integer; COND is an expression to be evaluated whenever\n\
+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 enabled temporarily,\n\
+so it will be disabled when hit. Equivalent to \"break\" followed\n\
+by using \"enable once\" on the breakpoint number.");
+
+ 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.\n\
+See the \"tbreak\" command which sets a breakpoint and enables it once.",
+ &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.\n\
+See the \"tbreak\" command which sets a breakpoint and enables it once.",
+ &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_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..5005450
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/breakpoint.h
@@ -0,0 +1,372 @@
+/* Data structures associated with breakpoints in GDB.
+ 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. */
+
+#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_until, /* used by until command */
+ bp_finish, /* used by finish command */
+ bp_watchpoint, /* Watchpoint */
+ 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,
+
+ /* 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 val;
+ /* Thread number for thread-specific breakpoint, or -1 if don't care */
+ int thread;
+};
+
+/* 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,
+
+ /* 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 the step resume breakpoint? This is separate from the
+ main_action to allow for it to be combined with any of the main
+ actions. */
+ int step_resume;
+
+ /* 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 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
+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));
+
+/* 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..dfa9be1
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/buildsym.c
@@ -0,0 +1,950 @@
+/* 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
+
+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)))
+ {
+ 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 : strdup (name);
+ subfile->dirname = (dirname == NULL) ? NULL : strdup (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 = strdup (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..e034863
--- /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.tab.c b/gnu/usr.bin/gdb/gdb/c-exp.tab.c
new file mode 100644
index 0000000..924dfc6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-exp.tab.c
@@ -0,0 +1,2648 @@
+#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 yyparse c_parse
+#define yylex c_lex
+#define yyerror c_error
+#define yychar c_char
+#define yyval c_val
+#define yylval c_lval
+#define yydebug c_debug
+#define yynerrs c_nerrs
+#define yyerrflag c_errflag
+#define yyss c_ss
+#define yyssp c_ssp
+#define yyvs c_vs
+#define yyvsp c_vsp
+#define yylhs c_lhs
+#define yylen c_len
+#define yydefred c_defred
+#define yydgoto c_dgoto
+#define yysindex c_sindex
+#define yyrindex c_rindex
+#define yygindex c_gindex
+#define yytable c_table
+#define yycheck c_check
+#define yyname c_name
+#define yyrule c_rule
+#define YYPREFIX "c_"
+#line 38 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+
+#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 *));
+
+#line 102 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+typedef 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;
+#line 125 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+/* YYSTYPE gets defined by %union */
+static int
+parse_number PARAMS ((char *, int, int, YYSTYPE *));
+#line 121 "y.tab.c"
+#define INT 257
+#define FLOAT 258
+#define STRING 259
+#define NAME 260
+#define TYPENAME 261
+#define NAME_OR_INT 262
+#define STRUCT 263
+#define CLASS 264
+#define UNION 265
+#define ENUM 266
+#define SIZEOF 267
+#define UNSIGNED 268
+#define COLONCOLON 269
+#define TEMPLATE 270
+#define ERROR 271
+#define SIGNED_KEYWORD 272
+#define LONG 273
+#define SHORT 274
+#define INT_KEYWORD 275
+#define CONST_KEYWORD 276
+#define VOLATILE_KEYWORD 277
+#define LAST 278
+#define REGNAME 279
+#define VARIABLE 280
+#define ASSIGN_MODIFY 281
+#define THIS 282
+#define ABOVE_COMMA 283
+#define OROR 284
+#define ANDAND 285
+#define EQUAL 286
+#define NOTEQUAL 287
+#define LEQ 288
+#define GEQ 289
+#define LSH 290
+#define RSH 291
+#define UNARY 292
+#define INCREMENT 293
+#define DECREMENT 294
+#define ARROW 295
+#define BLOCKNAME 296
+#define YYERRCODE 256
+short c_lhs[] = { -1,
+ 0, 0, 3, 2, 2, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 21, 1, 6, 20, 20, 20, 7, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 19, 19, 4, 5, 5,
+ 4, 4, 4, 14, 14, 14, 14, 14, 14, 13,
+ 13, 13, 13, 13, 12, 12, 12, 12, 12, 15,
+ 15, 11, 11, 8, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 18, 18, 18, 18, 10, 10, 16, 16, 16,
+ 16, 17, 17,
+};
+short c_len[] = { 2,
+ 1, 1, 1, 1, 3, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 3, 3, 4, 3, 3,
+ 4, 4, 0, 5, 1, 0, 1, 3, 1, 3,
+ 4, 4, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 5, 3, 3, 1, 1, 1, 1, 1,
+ 1, 1, 4, 1, 1, 1, 3, 3, 3, 4,
+ 1, 2, 1, 1, 2, 2, 2, 3, 3, 1,
+ 2, 1, 2, 1, 3, 2, 1, 2, 1, 2,
+ 3, 2, 3, 1, 3, 6, 8, 9, 1, 1,
+ 1, 1, 2, 3, 2, 3, 3, 4, 2, 3,
+ 2, 2, 2, 2, 2, 1, 2, 1, 5, 2,
+ 2, 1, 1, 1, 1, 1, 3, 1, 1, 1,
+ 1, 1, 1,
+};
+short c_defred[] = { 0,
+ 56, 58, 64, 132, 99, 57, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 100, 0, 0,
+ 60, 61, 62, 65, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 25, 0, 0, 0, 2, 59, 71,
+ 0, 0, 0, 94, 73, 0, 128, 130, 131, 129,
+ 111, 112, 113, 114, 0, 0, 0, 122, 0, 0,
+ 123, 115, 72, 0, 124, 125, 117, 0, 103, 109,
+ 120, 121, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 13, 14, 0, 0, 0, 23, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 89, 0, 77, 87, 0, 0, 0, 0, 104,
+ 110, 0, 106, 33, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 17,
+ 16, 0, 20, 19, 0, 0, 0, 29, 0, 0,
+ 30, 0, 95, 0, 69, 78, 79, 83, 81, 0,
+ 90, 92, 0, 0, 0, 0, 0, 88, 86, 0,
+ 0, 108, 0, 0, 0, 0, 0, 22, 0, 0,
+ 0, 0, 70, 91, 0, 0, 93, 85, 119, 0,
+ 24, 0, 0, 0, 0, 97, 0, 98,
+};
+short c_dgoto[] = { 35,
+ 36, 78, 38, 39, 40, 41, 169, 183, 57, 185,
+ 122, 123, 124, 44, 125, 175, 45, 62, 46, 113,
+ 166,
+};
+short c_sindex[] = { 1773,
+ 0, 0, 0, 0, 0, 0, -243, -243, -243, -243,
+ 1839, -240, -243, -243, -56, -260, -266, 0, 1303, 1303,
+ 0, 0, 0, 0, 1773, 1773, 1773, 1773, 1773, 1773,
+ 0, 1773, 1773, 0, 0, 2134, -24, 0, 0, 0,
+ 1773, -16, -36, 0, 0, -233, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1773, 83, -219, 0, -217, -208,
+ 0, 0, 0, 57, 0, 0, 0, -199, 0, 0,
+ 0, 0, 83, 83, 83, 83, 83, 74, -12, 83,
+ 83, 1773, 1773, 1773, 1773, 1773, 1773, 1773, 1773, 1773,
+ 1773, 1773, 1773, 1773, 1773, 1773, 1773, 1773, 1773, 1773,
+ 1773, 1773, 1773, 0, 0, 2136, 2175, 1773, 0, 1773,
+ 2134, -28, -17, 1303, -35, 31, 31, 31, 31, -90,
+ 1807, 0, -3, 0, 0, -243, 49, -52, -148, 0,
+ 0, 1303, 0, 0, 1773, 2134, 2134, 2099, 2197, 2208,
+ 2236, 2269, 2304, 2474, 2474, 743, 743, 743, 743, 615,
+ 615, 273, 320, 320, 83, 83, 83, 0, 1773, 0,
+ 0, 1773, 0, 0, -44, 1773, 2134, 0, 1773, 1773,
+ 0, -137, 0, -243, 0, 0, 0, 0, 0, 63,
+ 0, 0, -16, 28, 80, 117, 477, 0, 0, 0,
+ 1653, 0, -32, 83, 1773, 83, 83, 0, 106, 83,
+ 2134, 136, 0, 0, 145, 1303, 0, 0, 0, 2169,
+ 0, 129, -16, 155, 2276, 0, 171, 0,
+};
+short c_rindex[] = { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1146, 0, 0, 1403, 1413, 1691, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 16, 188, 0, 0, 0,
+ -13, 206, 79, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 213, 0, 0, 1716, 1721,
+ 0, 0, 0, 0, 0, 0, 0, 1730, 0, 0,
+ 0, 0, 311, 402, 414, 487, 515, 0, 0, 583,
+ 673, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -19, 0, 0, 0, 0, 10, 52, 111, 359, 0,
+ 0, 0, 492, 0, 0, 0, 0, 0, 1746, 0,
+ 0, 0, 0, 0, 0, 668, 892, 0, 881, 153,
+ 479, 1135, 128, 1583, 1620, 1366, 1438, 1546, 1572, 1264,
+ 1312, 1236, 1182, 1224, 782, 794, 853, 40, 0, 0,
+ 0, 0, 0, 0, 0, 193, 239, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 201, -30, 0, 0, 0, 0, 0, 99,
+ 138, 0, 0, 928, 0, 967, 1056, 0, 0, 1110,
+ -18, 0, 0, 0, 0, 0, 0, 0, 0, 110,
+ 0, 0, 257, 544, 0, 0, 0, 0,
+};
+short c_gindex[] = { 0,
+ 2543, 5, 0, 0, 42, 0, 107, 75, 450, 13,
+ 115, 0, 148, 0, 120, 989, 0, 215, 0, 81,
+ 0,
+};
+#define YYTABLESIZE 2769
+short c_table[] = { 110,
+ 133, 118, 181, 121, 37, 119, 173, 114, 70, 75,
+ 74, 114, 68, 74, 69, 4, 47, 48, 49, 110,
+ 58, 27, 28, 114, 27, 28, 170, 114, 135, 209,
+ 26, 74, 59, 60, 61, 126, 187, 133, 133, 130,
+ 133, 133, 133, 133, 133, 133, 133, 133, 198, 128,
+ 75, 76, 50, 75, 120, 129, 4, 130, 133, 4,
+ 133, 133, 133, 133, 133, 118, 131, 121, 118, 119,
+ 121, 75, 119, 174, 42, 133, 130, 130, 74, 130,
+ 130, 130, 130, 130, 130, 130, 130, 120, 114, 191,
+ 174, 133, 76, 133, 133, 76, 168, 130, 68, 130,
+ 130, 130, 130, 130, 79, 27, 28, 168, 4, 53,
+ 82, 26, 165, 76, 134, 112, 132, 110, 120, 74,
+ 207, 120, 109, 206, 133, 133, 192, 48, 107, 127,
+ 130, 202, 130, 130, 75, 68, 68, 63, 68, 68,
+ 68, 68, 68, 68, 68, 68, 211, 160, 163, 170,
+ 53, 82, 51, 53, 82, 204, 68, 208, 68, 68,
+ 68, 68, 68, 130, 130, 48, 180, 53, 48, 214,
+ 53, 48, 82, 108, 63, 63, 76, 212, 63, 63,
+ 63, 63, 63, 63, 63, 48, 173, 1, 48, 68,
+ 48, 68, 68, 51, 215, 63, 51, 63, 63, 63,
+ 63, 63, 53, 74, 58, 3, 193, 47, 48, 49,
+ 51, 218, 15, 51, 206, 51, 65, 66, 61, 171,
+ 48, 48, 68, 68, 47, 48, 49, 217, 63, 67,
+ 63, 63, 115, 26, 53, 82, 26, 188, 5, 116,
+ 117, 126, 189, 50, 126, 51, 199, 0, 0, 15,
+ 15, 48, 48, 15, 15, 15, 15, 15, 0, 15,
+ 50, 63, 63, 176, 177, 178, 179, 0, 186, 66,
+ 15, 0, 15, 15, 15, 15, 15, 51, 0, 5,
+ 213, 133, 5, 0, 133, 133, 133, 133, 133, 133,
+ 133, 133, 0, 133, 133, 133, 205, 127, 0, 0,
+ 127, 0, 0, 116, 117, 15, 15, 0, 99, 103,
+ 7, 0, 109, 0, 101, 99, 0, 100, 107, 102,
+ 130, 0, 0, 130, 130, 130, 130, 130, 130, 130,
+ 130, 5, 130, 130, 130, 0, 15, 15, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 7, 7, 0,
+ 0, 7, 7, 7, 7, 7, 103, 7, 80, 109,
+ 0, 101, 0, 108, 0, 107, 102, 67, 7, 0,
+ 7, 7, 7, 7, 7, 104, 105, 106, 0, 68,
+ 0, 0, 68, 68, 68, 68, 68, 68, 68, 68,
+ 53, 68, 68, 68, 0, 0, 0, 0, 0, 80,
+ 0, 8, 80, 7, 7, 0, 0, 0, 48, 0,
+ 108, 48, 48, 6, 0, 0, 0, 0, 63, 0,
+ 80, 63, 63, 63, 63, 63, 63, 63, 63, 0,
+ 0, 0, 63, 51, 7, 7, 51, 51, 8, 8,
+ 0, 0, 8, 8, 8, 8, 8, 0, 8, 43,
+ 6, 6, 0, 0, 6, 6, 6, 6, 6, 8,
+ 6, 8, 8, 8, 8, 8, 0, 0, 71, 72,
+ 0, 6, 0, 6, 6, 6, 6, 6, 50, 43,
+ 0, 0, 0, 80, 0, 0, 11, 0, 0, 0,
+ 43, 84, 0, 15, 8, 8, 15, 15, 15, 15,
+ 15, 15, 15, 15, 43, 0, 6, 6, 0, 0,
+ 0, 0, 0, 0, 12, 0, 0, 182, 0, 50,
+ 0, 0, 50, 11, 11, 8, 8, 11, 11, 11,
+ 11, 11, 84, 11, 0, 84, 50, 6, 6, 50,
+ 0, 50, 0, 96, 11, 0, 11, 11, 11, 11,
+ 11, 12, 12, 84, 0, 12, 12, 12, 12, 12,
+ 0, 12, 0, 172, 0, 104, 105, 106, 0, 0,
+ 184, 50, 12, 0, 12, 12, 12, 12, 12, 11,
+ 11, 184, 9, 0, 96, 0, 0, 96, 0, 0,
+ 0, 7, 0, 0, 7, 7, 7, 7, 7, 7,
+ 7, 7, 50, 50, 0, 96, 0, 12, 12, 0,
+ 11, 11, 104, 105, 106, 0, 84, 0, 0, 9,
+ 9, 0, 0, 9, 9, 9, 9, 9, 0, 9,
+ 0, 0, 0, 0, 0, 0, 184, 0, 12, 12,
+ 9, 0, 9, 9, 9, 9, 9, 0, 0, 0,
+ 0, 103, 0, 0, 109, 184, 101, 99, 0, 100,
+ 107, 102, 0, 0, 184, 0, 0, 55, 96, 0,
+ 0, 0, 10, 0, 0, 9, 9, 0, 98, 0,
+ 0, 0, 8, 0, 0, 8, 8, 8, 8, 8,
+ 8, 8, 8, 0, 6, 0, 0, 6, 6, 6,
+ 6, 6, 6, 6, 6, 108, 9, 9, 55, 10,
+ 10, 55, 0, 10, 10, 10, 10, 10, 0, 10,
+ 0, 0, 0, 0, 0, 55, 0, 0, 0, 0,
+ 10, 0, 10, 10, 10, 10, 10, 5, 0, 7,
+ 8, 9, 10, 0, 12, 0, 14, 0, 15, 16,
+ 17, 18, 19, 20, 0, 0, 0, 0, 0, 50,
+ 55, 0, 50, 50, 0, 10, 10, 11, 0, 0,
+ 11, 11, 11, 11, 11, 11, 11, 11, 0, 103,
+ 0, 35, 109, 0, 101, 99, 0, 100, 107, 102,
+ 0, 0, 55, 36, 0, 12, 10, 10, 12, 12,
+ 12, 12, 12, 12, 12, 12, 98, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 35, 35,
+ 0, 0, 35, 35, 35, 35, 35, 0, 35, 0,
+ 36, 36, 0, 108, 36, 36, 36, 36, 36, 35,
+ 36, 35, 35, 35, 35, 35, 0, 0, 0, 0,
+ 0, 36, 37, 36, 36, 36, 36, 36, 0, 0,
+ 0, 0, 0, 9, 0, 0, 9, 9, 9, 9,
+ 9, 9, 9, 9, 35, 35, 0, 0, 0, 0,
+ 52, 0, 0, 0, 0, 0, 36, 36, 0, 37,
+ 37, 54, 0, 37, 37, 37, 37, 37, 0, 37,
+ 0, 0, 0, 0, 0, 35, 35, 104, 105, 106,
+ 37, 0, 37, 37, 37, 37, 37, 36, 36, 0,
+ 0, 52, 0, 0, 52, 0, 0, 32, 0, 0,
+ 0, 0, 54, 0, 0, 54, 0, 0, 52, 0,
+ 0, 52, 0, 52, 0, 37, 37, 0, 0, 54,
+ 0, 0, 0, 10, 0, 0, 10, 10, 10, 10,
+ 10, 10, 10, 10, 32, 32, 18, 0, 32, 32,
+ 32, 32, 32, 52, 32, 0, 37, 37, 0, 0,
+ 0, 0, 0, 0, 54, 32, 0, 32, 32, 32,
+ 32, 32, 0, 0, 0, 51, 52, 53, 54, 0,
+ 0, 63, 64, 18, 18, 52, 0, 18, 18, 18,
+ 18, 18, 0, 18, 0, 0, 54, 0, 0, 0,
+ 32, 32, 0, 0, 18, 0, 18, 18, 18, 18,
+ 18, 0, 96, 97, 0, 104, 105, 106, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 32, 32, 0, 0, 21, 0, 0, 0, 18,
+ 18, 0, 35, 0, 0, 35, 35, 35, 35, 35,
+ 35, 35, 35, 0, 36, 0, 0, 36, 36, 36,
+ 36, 36, 36, 36, 36, 0, 0, 0, 0, 0,
+ 18, 18, 21, 21, 161, 164, 21, 21, 21, 21,
+ 21, 0, 21, 0, 0, 0, 0, 0, 0, 31,
+ 0, 0, 0, 21, 190, 21, 21, 21, 21, 21,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 37, 49, 0, 37, 37, 37, 37,
+ 37, 37, 37, 37, 0, 116, 31, 31, 21, 21,
+ 31, 31, 31, 31, 31, 0, 31, 0, 0, 0,
+ 0, 52, 203, 0, 52, 0, 0, 31, 0, 31,
+ 31, 31, 31, 31, 0, 49, 0, 0, 49, 21,
+ 21, 38, 0, 116, 0, 116, 116, 116, 0, 116,
+ 0, 0, 49, 0, 0, 49, 0, 49, 0, 0,
+ 0, 0, 31, 31, 0, 0, 0, 116, 32, 0,
+ 0, 32, 32, 32, 32, 32, 32, 32, 32, 38,
+ 0, 0, 38, 39, 38, 38, 38, 49, 49, 0,
+ 0, 0, 0, 31, 31, 34, 116, 0, 0, 38,
+ 0, 38, 38, 38, 38, 38, 0, 18, 0, 0,
+ 18, 18, 18, 18, 18, 18, 18, 18, 49, 49,
+ 0, 39, 0, 40, 39, 0, 39, 39, 39, 0,
+ 116, 0, 0, 34, 38, 38, 34, 0, 0, 34,
+ 0, 39, 0, 39, 39, 39, 39, 39, 0, 0,
+ 0, 0, 0, 34, 0, 34, 34, 34, 34, 34,
+ 0, 40, 0, 0, 40, 38, 38, 40, 0, 0,
+ 0, 41, 0, 0, 0, 0, 39, 39, 0, 0,
+ 0, 40, 0, 40, 40, 40, 40, 0, 34, 34,
+ 0, 0, 0, 0, 0, 0, 21, 0, 0, 21,
+ 21, 21, 21, 21, 21, 21, 21, 39, 39, 41,
+ 0, 0, 41, 0, 0, 41, 40, 40, 0, 34,
+ 34, 0, 0, 0, 0, 46, 0, 0, 0, 41,
+ 0, 41, 41, 41, 41, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 40, 40, 0,
+ 31, 0, 0, 31, 31, 31, 31, 31, 31, 31,
+ 31, 0, 118, 46, 41, 41, 46, 0, 0, 46,
+ 0, 0, 101, 0, 116, 49, 0, 0, 49, 49,
+ 0, 116, 116, 46, 0, 46, 46, 46, 46, 0,
+ 0, 0, 0, 0, 0, 41, 41, 47, 0, 0,
+ 118, 0, 118, 118, 118, 0, 118, 0, 0, 0,
+ 101, 0, 101, 101, 101, 0, 101, 0, 46, 46,
+ 0, 0, 38, 0, 118, 38, 38, 38, 38, 38,
+ 38, 38, 38, 0, 101, 47, 0, 0, 47, 0,
+ 0, 47, 0, 0, 0, 0, 0, 0, 0, 46,
+ 46, 0, 0, 118, 0, 47, 0, 47, 47, 47,
+ 47, 0, 0, 101, 39, 0, 0, 39, 39, 39,
+ 39, 39, 39, 39, 39, 0, 34, 0, 0, 34,
+ 34, 34, 34, 34, 34, 34, 34, 118, 0, 0,
+ 47, 47, 0, 0, 0, 0, 0, 101, 0, 0,
+ 0, 0, 0, 0, 40, 44, 0, 40, 40, 40,
+ 40, 40, 40, 40, 40, 0, 0, 0, 0, 0,
+ 0, 47, 47, 5, 0, 7, 8, 9, 10, 0,
+ 12, 45, 14, 0, 15, 16, 17, 18, 19, 20,
+ 0, 0, 42, 44, 0, 0, 44, 0, 0, 44,
+ 0, 0, 41, 0, 0, 41, 41, 41, 41, 41,
+ 41, 41, 41, 44, 0, 44, 44, 44, 44, 45,
+ 0, 0, 45, 0, 0, 45, 0, 0, 0, 43,
+ 42, 0, 0, 42, 0, 0, 42, 0, 0, 45,
+ 0, 45, 45, 45, 45, 0, 0, 0, 44, 44,
+ 42, 0, 0, 42, 0, 42, 46, 0, 0, 46,
+ 46, 46, 46, 46, 46, 0, 0, 43, 0, 0,
+ 43, 0, 0, 43, 45, 45, 0, 0, 0, 44,
+ 44, 118, 0, 0, 0, 42, 42, 43, 118, 118,
+ 43, 101, 43, 0, 0, 32, 0, 0, 101, 101,
+ 102, 0, 30, 0, 0, 45, 45, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 42, 42, 0, 0,
+ 0, 0, 43, 43, 0, 124, 0, 0, 47, 0,
+ 125, 47, 47, 47, 47, 47, 47, 0, 102, 105,
+ 102, 102, 102, 0, 102, 0, 0, 0, 0, 0,
+ 0, 0, 0, 43, 43, 107, 0, 0, 0, 0,
+ 0, 0, 102, 124, 0, 124, 124, 124, 125, 124,
+ 125, 125, 125, 0, 125, 0, 0, 105, 0, 105,
+ 105, 105, 0, 105, 0, 34, 0, 124, 33, 0,
+ 0, 102, 125, 107, 0, 107, 107, 107, 0, 107,
+ 0, 105, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 32, 124, 107, 0, 0,
+ 25, 125, 30, 0, 27, 102, 0, 26, 0, 0,
+ 105, 0, 0, 0, 0, 0, 44, 0, 0, 44,
+ 44, 44, 44, 44, 44, 0, 107, 0, 0, 0,
+ 124, 0, 0, 0, 118, 125, 121, 182, 119, 0,
+ 0, 0, 45, 0, 105, 45, 45, 45, 45, 45,
+ 45, 0, 0, 42, 0, 0, 42, 42, 42, 42,
+ 107, 32, 0, 0, 0, 0, 25, 0, 55, 0,
+ 27, 0, 0, 26, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 34, 0, 120, 33, 0,
+ 43, 0, 0, 43, 43, 43, 43, 0, 0, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 0, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 0, 24, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 28, 29, 0, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 102,
+ 0, 34, 0, 0, 33, 0, 102, 102, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 124, 0, 0, 0, 0, 125,
+ 0, 124, 124, 0, 0, 0, 125, 125, 105, 0,
+ 0, 0, 0, 0, 0, 105, 105, 0, 0, 0,
+ 0, 0, 0, 0, 107, 0, 0, 0, 0, 0,
+ 0, 107, 107, 0, 0, 0, 0, 0, 0, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 0, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 0, 24, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 28, 29, 5, 31, 7,
+ 8, 9, 10, 0, 12, 0, 14, 0, 15, 16,
+ 17, 18, 19, 20, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 0,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 0,
+ 24, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 28, 29, 0, 31, 103, 89, 0, 109, 0,
+ 101, 99, 0, 100, 107, 102, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 195, 0, 92, 83,
+ 93, 84, 98, 0, 0, 0, 0, 0, 0, 0,
+ 103, 89, 0, 109, 0, 101, 99, 159, 100, 107,
+ 102, 0, 0, 0, 0, 0, 0, 0, 0, 108,
+ 0, 0, 88, 92, 83, 93, 84, 98, 0, 0,
+ 0, 0, 0, 0, 0, 103, 89, 0, 109, 0,
+ 101, 99, 0, 100, 107, 102, 162, 0, 0, 0,
+ 0, 0, 87, 0, 108, 0, 0, 88, 92, 0,
+ 93, 84, 98, 103, 89, 0, 109, 0, 101, 99,
+ 0, 100, 107, 102, 103, 89, 0, 109, 0, 101,
+ 99, 0, 100, 107, 102, 0, 92, 87, 93, 108,
+ 98, 0, 88, 0, 0, 0, 0, 92, 0, 93,
+ 0, 98, 103, 89, 0, 109, 0, 101, 99, 0,
+ 100, 107, 102, 0, 0, 0, 0, 108, 0, 0,
+ 88, 0, 87, 0, 0, 92, 0, 93, 108, 98,
+ 0, 88, 0, 0, 0, 103, 89, 0, 109, 0,
+ 101, 99, 0, 100, 107, 102, 216, 0, 0, 0,
+ 87, 0, 0, 0, 0, 0, 108, 0, 92, 88,
+ 93, 87, 98, 0, 0, 0, 0, 0, 0, 0,
+ 103, 0, 0, 109, 0, 101, 99, 0, 100, 107,
+ 102, 0, 0, 0, 0, 0, 0, 0, 0, 108,
+ 0, 0, 0, 92, 0, 93, 0, 98, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 82,
+ 0, 0, 85, 86, 90, 91, 94, 95, 96, 97,
+ 0, 104, 105, 106, 108, 47, 158, 49, 7, 8,
+ 9, 10, 0, 12, 0, 14, 0, 15, 16, 17,
+ 18, 19, 20, 0, 82, 0, 0, 85, 86, 90,
+ 91, 94, 95, 96, 97, 0, 104, 105, 106, 0,
+ 0, 50, 0, 0, 47, 158, 49, 7, 8, 9,
+ 10, 0, 12, 0, 14, 0, 15, 16, 17, 18,
+ 19, 20, 85, 86, 90, 91, 94, 95, 96, 97,
+ 0, 104, 105, 106, 0, 0, 0, 0, 0, 0,
+ 50, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 86, 90, 91, 94, 95, 96, 97, 0, 104,
+ 105, 106, 0, 90, 91, 94, 95, 96, 97, 0,
+ 104, 105, 106, 0, 0, 0, 0, 0, 0, 0,
+ 103, 0, 0, 109, 0, 101, 99, 0, 100, 107,
+ 102, 90, 91, 94, 95, 96, 97, 0, 104, 105,
+ 106, 0, 0, 92, 0, 93, 5, 98, 7, 8,
+ 9, 10, 0, 12, 0, 14, 0, 15, 16, 17,
+ 18, 19, 20, 56, 90, 91, 94, 95, 96, 97,
+ 0, 104, 105, 106, 108, 0, 0, 73, 74, 75,
+ 76, 77, 0, 0, 80, 81, 0, 0, 0, 0,
+ 0, 0, 0, 111, 0, 0, 0, 0, 0, 90,
+ 91, 94, 95, 96, 97, 0, 104, 105, 106, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 136, 137, 138, 139, 140, 141,
+ 142, 143, 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153, 154, 155, 156, 157, 0, 0, 0, 0,
+ 0, 0, 167, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 194, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 196, 0, 0, 197, 0, 0, 0, 111, 0,
+ 0, 200, 201, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 194, 0, 0, 0, 210, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 94, 95, 96, 97, 0, 104, 105, 106,
+};
+short c_check[] = { 44,
+ 0, 38, 93, 40, 0, 42, 42, 40, 275, 0,
+ 41, 40, 273, 44, 275, 0, 260, 261, 262, 44,
+ 261, 41, 41, 40, 44, 44, 44, 40, 41, 62,
+ 44, 62, 273, 274, 275, 269, 40, 37, 38, 0,
+ 40, 41, 42, 43, 44, 45, 46, 47, 93, 269,
+ 41, 0, 296, 44, 91, 273, 41, 275, 58, 44,
+ 60, 61, 62, 63, 64, 38, 275, 40, 38, 42,
+ 40, 62, 42, 126, 0, 275, 37, 38, 0, 40,
+ 41, 42, 43, 44, 45, 46, 47, 91, 40, 41,
+ 126, 91, 41, 93, 94, 44, 125, 58, 0, 60,
+ 61, 62, 63, 64, 30, 125, 125, 125, 93, 0,
+ 0, 125, 108, 62, 41, 41, 60, 44, 91, 41,
+ 41, 91, 40, 44, 124, 125, 275, 0, 46, 55,
+ 91, 269, 93, 94, 125, 37, 38, 0, 40, 41,
+ 42, 43, 44, 45, 46, 47, 41, 106, 107, 44,
+ 41, 41, 0, 44, 44, 93, 58, 41, 60, 61,
+ 62, 63, 64, 124, 125, 38, 257, 58, 41, 41,
+ 61, 44, 62, 91, 37, 38, 125, 42, 41, 42,
+ 43, 44, 45, 46, 47, 58, 42, 0, 61, 91,
+ 63, 93, 94, 41, 40, 58, 44, 60, 61, 62,
+ 63, 64, 93, 125, 261, 0, 132, 260, 261, 262,
+ 58, 41, 0, 61, 44, 63, 273, 274, 275, 113,
+ 93, 94, 124, 125, 260, 261, 262, 215, 91, 15,
+ 93, 94, 269, 41, 125, 125, 44, 123, 0, 276,
+ 277, 41, 123, 296, 44, 93, 166, -1, -1, 37,
+ 38, 124, 125, 41, 42, 43, 44, 45, -1, 47,
+ 296, 124, 125, 116, 117, 118, 119, -1, 121, 269,
+ 58, -1, 60, 61, 62, 63, 64, 125, -1, 41,
+ 206, 281, 44, -1, 284, 285, 286, 287, 288, 289,
+ 290, 291, -1, 293, 294, 295, 269, 41, -1, -1,
+ 44, -1, -1, 276, 277, 93, 94, -1, 269, 37,
+ 0, -1, 40, -1, 42, 43, -1, 45, 46, 47,
+ 281, -1, -1, 284, 285, 286, 287, 288, 289, 290,
+ 291, 93, 293, 294, 295, -1, 124, 125, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 37, 38, -1,
+ -1, 41, 42, 43, 44, 45, 37, 47, 0, 40,
+ -1, 42, -1, 91, -1, 46, 47, 269, 58, -1,
+ 60, 61, 62, 63, 64, 293, 294, 295, -1, 281,
+ -1, -1, 284, 285, 286, 287, 288, 289, 290, 291,
+ 281, 293, 294, 295, -1, -1, -1, -1, -1, 41,
+ -1, 0, 44, 93, 94, -1, -1, -1, 281, -1,
+ 91, 284, 285, 0, -1, -1, -1, -1, 281, -1,
+ 62, 284, 285, 286, 287, 288, 289, 290, 291, -1,
+ -1, -1, 295, 281, 124, 125, 284, 285, 37, 38,
+ -1, -1, 41, 42, 43, 44, 45, -1, 47, 0,
+ 37, 38, -1, -1, 41, 42, 43, 44, 45, 58,
+ 47, 60, 61, 62, 63, 64, -1, -1, 19, 20,
+ -1, 58, -1, 60, 61, 62, 63, 64, 0, 30,
+ -1, -1, -1, 125, -1, -1, 0, -1, -1, -1,
+ 41, 0, -1, 281, 93, 94, 284, 285, 286, 287,
+ 288, 289, 290, 291, 55, -1, 93, 94, -1, -1,
+ -1, -1, -1, -1, 0, -1, -1, 41, -1, 41,
+ -1, -1, 44, 37, 38, 124, 125, 41, 42, 43,
+ 44, 45, 41, 47, -1, 44, 58, 124, 125, 61,
+ -1, 63, -1, 0, 58, -1, 60, 61, 62, 63,
+ 64, 37, 38, 62, -1, 41, 42, 43, 44, 45,
+ -1, 47, -1, 114, -1, 293, 294, 295, -1, -1,
+ 121, 93, 58, -1, 60, 61, 62, 63, 64, 93,
+ 94, 132, 0, -1, 41, -1, -1, 44, -1, -1,
+ -1, 281, -1, -1, 284, 285, 286, 287, 288, 289,
+ 290, 291, 124, 125, -1, 62, -1, 93, 94, -1,
+ 124, 125, 293, 294, 295, -1, 125, -1, -1, 37,
+ 38, -1, -1, 41, 42, 43, 44, 45, -1, 47,
+ -1, -1, -1, -1, -1, -1, 187, -1, 124, 125,
+ 58, -1, 60, 61, 62, 63, 64, -1, -1, -1,
+ -1, 37, -1, -1, 40, 206, 42, 43, -1, 45,
+ 46, 47, -1, -1, 215, -1, -1, 0, 125, -1,
+ -1, -1, 0, -1, -1, 93, 94, -1, 64, -1,
+ -1, -1, 281, -1, -1, 284, 285, 286, 287, 288,
+ 289, 290, 291, -1, 281, -1, -1, 284, 285, 286,
+ 287, 288, 289, 290, 291, 91, 124, 125, 41, 37,
+ 38, 44, -1, 41, 42, 43, 44, 45, -1, 47,
+ -1, -1, -1, -1, -1, 58, -1, -1, -1, -1,
+ 58, -1, 60, 61, 62, 63, 64, 261, -1, 263,
+ 264, 265, 266, -1, 268, -1, 270, -1, 272, 273,
+ 274, 275, 276, 277, -1, -1, -1, -1, -1, 281,
+ 93, -1, 284, 285, -1, 93, 94, 281, -1, -1,
+ 284, 285, 286, 287, 288, 289, 290, 291, -1, 37,
+ -1, 0, 40, -1, 42, 43, -1, 45, 46, 47,
+ -1, -1, 125, 0, -1, 281, 124, 125, 284, 285,
+ 286, 287, 288, 289, 290, 291, 64, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 37, 38,
+ -1, -1, 41, 42, 43, 44, 45, -1, 47, -1,
+ 37, 38, -1, 91, 41, 42, 43, 44, 45, 58,
+ 47, 60, 61, 62, 63, 64, -1, -1, -1, -1,
+ -1, 58, 0, 60, 61, 62, 63, 64, -1, -1,
+ -1, -1, -1, 281, -1, -1, 284, 285, 286, 287,
+ 288, 289, 290, 291, 93, 94, -1, -1, -1, -1,
+ 0, -1, -1, -1, -1, -1, 93, 94, -1, 37,
+ 38, 0, -1, 41, 42, 43, 44, 45, -1, 47,
+ -1, -1, -1, -1, -1, 124, 125, 293, 294, 295,
+ 58, -1, 60, 61, 62, 63, 64, 124, 125, -1,
+ -1, 41, -1, -1, 44, -1, -1, 0, -1, -1,
+ -1, -1, 41, -1, -1, 44, -1, -1, 58, -1,
+ -1, 61, -1, 63, -1, 93, 94, -1, -1, 58,
+ -1, -1, -1, 281, -1, -1, 284, 285, 286, 287,
+ 288, 289, 290, 291, 37, 38, 0, -1, 41, 42,
+ 43, 44, 45, 93, 47, -1, 124, 125, -1, -1,
+ -1, -1, -1, -1, 93, 58, -1, 60, 61, 62,
+ 63, 64, -1, -1, -1, 7, 8, 9, 10, -1,
+ -1, 13, 14, 37, 38, 125, -1, 41, 42, 43,
+ 44, 45, -1, 47, -1, -1, 125, -1, -1, -1,
+ 93, 94, -1, -1, 58, -1, 60, 61, 62, 63,
+ 64, -1, 290, 291, -1, 293, 294, 295, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 124, 125, -1, -1, 0, -1, -1, -1, 93,
+ 94, -1, 281, -1, -1, 284, 285, 286, 287, 288,
+ 289, 290, 291, -1, 281, -1, -1, 284, 285, 286,
+ 287, 288, 289, 290, 291, -1, -1, -1, -1, -1,
+ 124, 125, 37, 38, 106, 107, 41, 42, 43, 44,
+ 45, -1, 47, -1, -1, -1, -1, -1, -1, 0,
+ -1, -1, -1, 58, 126, 60, 61, 62, 63, 64,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 281, 0, -1, 284, 285, 286, 287,
+ 288, 289, 290, 291, -1, 0, 37, 38, 93, 94,
+ 41, 42, 43, 44, 45, -1, 47, -1, -1, -1,
+ -1, 281, 174, -1, 284, -1, -1, 58, -1, 60,
+ 61, 62, 63, 64, -1, 41, -1, -1, 44, 124,
+ 125, 0, -1, 38, -1, 40, 41, 42, -1, 44,
+ -1, -1, 58, -1, -1, 61, -1, 63, -1, -1,
+ -1, -1, 93, 94, -1, -1, -1, 62, 281, -1,
+ -1, 284, 285, 286, 287, 288, 289, 290, 291, 38,
+ -1, -1, 41, 0, 43, 44, 45, 93, 94, -1,
+ -1, -1, -1, 124, 125, 0, 91, -1, -1, 58,
+ -1, 60, 61, 62, 63, 64, -1, 281, -1, -1,
+ 284, 285, 286, 287, 288, 289, 290, 291, 124, 125,
+ -1, 38, -1, 0, 41, -1, 43, 44, 45, -1,
+ 125, -1, -1, 38, 93, 94, 41, -1, -1, 44,
+ -1, 58, -1, 60, 61, 62, 63, 64, -1, -1,
+ -1, -1, -1, 58, -1, 60, 61, 62, 63, 64,
+ -1, 38, -1, -1, 41, 124, 125, 44, -1, -1,
+ -1, 0, -1, -1, -1, -1, 93, 94, -1, -1,
+ -1, 58, -1, 60, 61, 62, 63, -1, 93, 94,
+ -1, -1, -1, -1, -1, -1, 281, -1, -1, 284,
+ 285, 286, 287, 288, 289, 290, 291, 124, 125, 38,
+ -1, -1, 41, -1, -1, 44, 93, 94, -1, 124,
+ 125, -1, -1, -1, -1, 0, -1, -1, -1, 58,
+ -1, 60, 61, 62, 63, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 124, 125, -1,
+ 281, -1, -1, 284, 285, 286, 287, 288, 289, 290,
+ 291, -1, 0, 38, 93, 94, 41, -1, -1, 44,
+ -1, -1, 0, -1, 269, 281, -1, -1, 284, 285,
+ -1, 276, 277, 58, -1, 60, 61, 62, 63, -1,
+ -1, -1, -1, -1, -1, 124, 125, 0, -1, -1,
+ 38, -1, 40, 41, 42, -1, 44, -1, -1, -1,
+ 38, -1, 40, 41, 42, -1, 44, -1, 93, 94,
+ -1, -1, 281, -1, 62, 284, 285, 286, 287, 288,
+ 289, 290, 291, -1, 62, 38, -1, -1, 41, -1,
+ -1, 44, -1, -1, -1, -1, -1, -1, -1, 124,
+ 125, -1, -1, 91, -1, 58, -1, 60, 61, 62,
+ 63, -1, -1, 91, 281, -1, -1, 284, 285, 286,
+ 287, 288, 289, 290, 291, -1, 281, -1, -1, 284,
+ 285, 286, 287, 288, 289, 290, 291, 125, -1, -1,
+ 93, 94, -1, -1, -1, -1, -1, 125, -1, -1,
+ -1, -1, -1, -1, 281, 0, -1, 284, 285, 286,
+ 287, 288, 289, 290, 291, -1, -1, -1, -1, -1,
+ -1, 124, 125, 261, -1, 263, 264, 265, 266, -1,
+ 268, 0, 270, -1, 272, 273, 274, 275, 276, 277,
+ -1, -1, 0, 38, -1, -1, 41, -1, -1, 44,
+ -1, -1, 281, -1, -1, 284, 285, 286, 287, 288,
+ 289, 290, 291, 58, -1, 60, 61, 62, 63, 38,
+ -1, -1, 41, -1, -1, 44, -1, -1, -1, 0,
+ 38, -1, -1, 41, -1, -1, 44, -1, -1, 58,
+ -1, 60, 61, 62, 63, -1, -1, -1, 93, 94,
+ 58, -1, -1, 61, -1, 63, 281, -1, -1, 284,
+ 285, 286, 287, 288, 289, -1, -1, 38, -1, -1,
+ 41, -1, -1, 44, 93, 94, -1, -1, -1, 124,
+ 125, 269, -1, -1, -1, 93, 94, 58, 276, 277,
+ 61, 269, 63, -1, -1, 33, -1, -1, 276, 277,
+ 0, -1, 40, -1, -1, 124, 125, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 124, 125, -1, -1,
+ -1, -1, 93, 94, -1, 0, -1, -1, 281, -1,
+ 0, 284, 285, 286, 287, 288, 289, -1, 38, 0,
+ 40, 41, 42, -1, 44, -1, -1, -1, -1, -1,
+ -1, -1, -1, 124, 125, 0, -1, -1, -1, -1,
+ -1, -1, 62, 38, -1, 40, 41, 42, 38, 44,
+ 40, 41, 42, -1, 44, -1, -1, 38, -1, 40,
+ 41, 42, -1, 44, -1, 123, -1, 62, 126, -1,
+ -1, 91, 62, 38, -1, 40, 41, 42, -1, 44,
+ -1, 62, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 33, 91, 62, -1, -1,
+ 38, 91, 40, -1, 42, 125, -1, 45, -1, -1,
+ 91, -1, -1, -1, -1, -1, 281, -1, -1, 284,
+ 285, 286, 287, 288, 289, -1, 91, -1, -1, -1,
+ 125, -1, -1, -1, 38, 125, 40, 41, 42, -1,
+ -1, -1, 281, -1, 125, 284, 285, 286, 287, 288,
+ 289, -1, -1, 281, -1, -1, 284, 285, 286, 287,
+ 125, 33, -1, -1, -1, -1, 38, -1, 40, -1,
+ 42, -1, -1, 45, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 123, -1, 91, 126, -1,
+ 281, -1, -1, 284, 285, 286, 287, -1, -1, 257,
+ 258, 259, 260, 261, 262, 263, 264, 265, 266, 267,
+ 268, 269, 270, -1, 272, 273, 274, 275, 276, 277,
+ 278, 279, 280, -1, 282, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 293, 294, -1, 296, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 269,
+ -1, 123, -1, -1, 126, -1, 276, 277, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 269, -1, -1, -1, -1, 269,
+ -1, 276, 277, -1, -1, -1, 276, 277, 269, -1,
+ -1, -1, -1, -1, -1, 276, 277, -1, -1, -1,
+ -1, -1, -1, -1, 269, -1, -1, -1, -1, -1,
+ -1, 276, 277, -1, -1, -1, -1, -1, -1, 257,
+ 258, 259, 260, 261, 262, 263, 264, 265, 266, 267,
+ 268, 269, 270, -1, 272, 273, 274, 275, 276, 277,
+ 278, 279, 280, -1, 282, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 293, 294, 261, 296, 263,
+ 264, 265, 266, -1, 268, -1, 270, -1, 272, 273,
+ 274, 275, 276, 277, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 257, 258, 259, 260, 261,
+ 262, 263, 264, 265, 266, 267, 268, 269, 270, -1,
+ 272, 273, 274, 275, 276, 277, 278, 279, 280, -1,
+ 282, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 293, 294, -1, 296, 37, 38, -1, 40, -1,
+ 42, 43, -1, 45, 46, 47, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 58, -1, 60, 61,
+ 62, 63, 64, -1, -1, -1, -1, -1, -1, -1,
+ 37, 38, -1, 40, -1, 42, 43, 42, 45, 46,
+ 47, -1, -1, -1, -1, -1, -1, -1, -1, 91,
+ -1, -1, 94, 60, 61, 62, 63, 64, -1, -1,
+ -1, -1, -1, -1, -1, 37, 38, -1, 40, -1,
+ 42, 43, -1, 45, 46, 47, 42, -1, -1, -1,
+ -1, -1, 124, -1, 91, -1, -1, 94, 60, -1,
+ 62, 63, 64, 37, 38, -1, 40, -1, 42, 43,
+ -1, 45, 46, 47, 37, 38, -1, 40, -1, 42,
+ 43, -1, 45, 46, 47, -1, 60, 124, 62, 91,
+ 64, -1, 94, -1, -1, -1, -1, 60, -1, 62,
+ -1, 64, 37, 38, -1, 40, -1, 42, 43, -1,
+ 45, 46, 47, -1, -1, -1, -1, 91, -1, -1,
+ 94, -1, 124, -1, -1, 60, -1, 62, 91, 64,
+ -1, 94, -1, -1, -1, 37, 38, -1, 40, -1,
+ 42, 43, -1, 45, 46, 47, 41, -1, -1, -1,
+ 124, -1, -1, -1, -1, -1, 91, -1, 60, 94,
+ 62, 124, 64, -1, -1, -1, -1, -1, -1, -1,
+ 37, -1, -1, 40, -1, 42, 43, -1, 45, 46,
+ 47, -1, -1, -1, -1, -1, -1, -1, -1, 91,
+ -1, -1, -1, 60, -1, 62, -1, 64, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 281,
+ -1, -1, 284, 285, 286, 287, 288, 289, 290, 291,
+ -1, 293, 294, 295, 91, 260, 261, 262, 263, 264,
+ 265, 266, -1, 268, -1, 270, -1, 272, 273, 274,
+ 275, 276, 277, -1, 281, -1, -1, 284, 285, 286,
+ 287, 288, 289, 290, 291, -1, 293, 294, 295, -1,
+ -1, 296, -1, -1, 260, 261, 262, 263, 264, 265,
+ 266, -1, 268, -1, 270, -1, 272, 273, 274, 275,
+ 276, 277, 284, 285, 286, 287, 288, 289, 290, 291,
+ -1, 293, 294, 295, -1, -1, -1, -1, -1, -1,
+ 296, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 285, 286, 287, 288, 289, 290, 291, -1, 293,
+ 294, 295, -1, 286, 287, 288, 289, 290, 291, -1,
+ 293, 294, 295, -1, -1, -1, -1, -1, -1, -1,
+ 37, -1, -1, 40, -1, 42, 43, -1, 45, 46,
+ 47, 286, 287, 288, 289, 290, 291, -1, 293, 294,
+ 295, -1, -1, 60, -1, 62, 261, 64, 263, 264,
+ 265, 266, -1, 268, -1, 270, -1, 272, 273, 274,
+ 275, 276, 277, 11, 286, 287, 288, 289, 290, 291,
+ -1, 293, 294, 295, 91, -1, -1, 25, 26, 27,
+ 28, 29, -1, -1, 32, 33, -1, -1, -1, -1,
+ -1, -1, -1, 41, -1, -1, -1, -1, -1, 286,
+ 287, 288, 289, 290, 291, -1, 293, 294, 295, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ 98, 99, 100, 101, 102, 103, -1, -1, -1, -1,
+ -1, -1, 110, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 135, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 159, -1, -1, 162, -1, -1, -1, 166, -1,
+ -1, 169, 170, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 191, -1, -1, -1, 195, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 288, 289, 290, 291, -1, 293, 294, 295,
+};
+#define YYFINAL 35
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 296
+#if YYDEBUG
+char *c_name[] = {
+"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,"INT","FLOAT",
+"STRING","NAME","TYPENAME","NAME_OR_INT","STRUCT","CLASS","UNION","ENUM",
+"SIZEOF","UNSIGNED","COLONCOLON","TEMPLATE","ERROR","SIGNED_KEYWORD","LONG",
+"SHORT","INT_KEYWORD","CONST_KEYWORD","VOLATILE_KEYWORD","LAST","REGNAME",
+"VARIABLE","ASSIGN_MODIFY","THIS","ABOVE_COMMA","OROR","ANDAND","EQUAL",
+"NOTEQUAL","LEQ","GEQ","LSH","RSH","UNARY","INCREMENT","DECREMENT","ARROW",
+"BLOCKNAME",
+};
+char *c_rule[] = {
+"$accept : start",
+"start : exp1",
+"start : type_exp",
+"type_exp : type",
+"exp1 : exp",
+"exp1 : exp1 ',' exp",
+"exp : '*' exp",
+"exp : '&' exp",
+"exp : '-' exp",
+"exp : '!' exp",
+"exp : '~' exp",
+"exp : INCREMENT exp",
+"exp : DECREMENT exp",
+"exp : exp INCREMENT",
+"exp : exp DECREMENT",
+"exp : SIZEOF exp",
+"exp : exp ARROW name",
+"exp : exp ARROW qualified_name",
+"exp : exp ARROW '*' exp",
+"exp : exp '.' name",
+"exp : exp '.' qualified_name",
+"exp : exp '.' '*' exp",
+"exp : exp '[' exp1 ']'",
+"$$1 :",
+"exp : exp '(' $$1 arglist ')'",
+"lcurly : '{'",
+"arglist :",
+"arglist : exp",
+"arglist : arglist ',' exp",
+"rcurly : '}'",
+"exp : lcurly arglist rcurly",
+"exp : lcurly type rcurly exp",
+"exp : '(' type ')' exp",
+"exp : '(' exp1 ')'",
+"exp : exp '@' exp",
+"exp : exp '*' exp",
+"exp : exp '/' exp",
+"exp : exp '%' exp",
+"exp : exp '+' exp",
+"exp : exp '-' exp",
+"exp : exp LSH exp",
+"exp : exp RSH exp",
+"exp : exp EQUAL exp",
+"exp : exp NOTEQUAL exp",
+"exp : exp LEQ exp",
+"exp : exp GEQ exp",
+"exp : exp '<' exp",
+"exp : exp '>' exp",
+"exp : exp '&' exp",
+"exp : exp '^' exp",
+"exp : exp '|' exp",
+"exp : exp ANDAND exp",
+"exp : exp OROR exp",
+"exp : exp '?' exp ':' exp",
+"exp : exp '=' exp",
+"exp : exp ASSIGN_MODIFY exp",
+"exp : INT",
+"exp : NAME_OR_INT",
+"exp : FLOAT",
+"exp : variable",
+"exp : LAST",
+"exp : REGNAME",
+"exp : VARIABLE",
+"exp : SIZEOF '(' type ')'",
+"exp : STRING",
+"exp : THIS",
+"block : BLOCKNAME",
+"block : block COLONCOLON name",
+"variable : block COLONCOLON name",
+"qualified_name : typebase COLONCOLON name",
+"qualified_name : typebase COLONCOLON '~' name",
+"variable : qualified_name",
+"variable : COLONCOLON name",
+"variable : name_not_typename",
+"ptype : typebase",
+"ptype : typebase CONST_KEYWORD",
+"ptype : typebase VOLATILE_KEYWORD",
+"ptype : typebase abs_decl",
+"ptype : typebase CONST_KEYWORD abs_decl",
+"ptype : typebase VOLATILE_KEYWORD abs_decl",
+"abs_decl : '*'",
+"abs_decl : '*' abs_decl",
+"abs_decl : '&'",
+"abs_decl : '&' abs_decl",
+"abs_decl : direct_abs_decl",
+"direct_abs_decl : '(' abs_decl ')'",
+"direct_abs_decl : direct_abs_decl array_mod",
+"direct_abs_decl : array_mod",
+"direct_abs_decl : direct_abs_decl func_mod",
+"direct_abs_decl : func_mod",
+"array_mod : '[' ']'",
+"array_mod : '[' INT ']'",
+"func_mod : '(' ')'",
+"func_mod : '(' nonempty_typelist ')'",
+"type : ptype",
+"type : typebase COLONCOLON '*'",
+"type : type '(' typebase COLONCOLON '*' ')'",
+"type : type '(' typebase COLONCOLON '*' ')' '(' ')'",
+"type : type '(' typebase COLONCOLON '*' ')' '(' nonempty_typelist ')'",
+"typebase : TYPENAME",
+"typebase : INT_KEYWORD",
+"typebase : LONG",
+"typebase : SHORT",
+"typebase : LONG INT_KEYWORD",
+"typebase : UNSIGNED LONG INT_KEYWORD",
+"typebase : LONG LONG",
+"typebase : LONG LONG INT_KEYWORD",
+"typebase : UNSIGNED LONG LONG",
+"typebase : UNSIGNED LONG LONG INT_KEYWORD",
+"typebase : SHORT INT_KEYWORD",
+"typebase : UNSIGNED SHORT INT_KEYWORD",
+"typebase : STRUCT name",
+"typebase : CLASS name",
+"typebase : UNION name",
+"typebase : ENUM name",
+"typebase : UNSIGNED typename",
+"typebase : UNSIGNED",
+"typebase : SIGNED_KEYWORD typename",
+"typebase : SIGNED_KEYWORD",
+"typebase : TEMPLATE name '<' type '>'",
+"typebase : CONST_KEYWORD typebase",
+"typebase : VOLATILE_KEYWORD typebase",
+"typename : TYPENAME",
+"typename : INT_KEYWORD",
+"typename : LONG",
+"typename : SHORT",
+"nonempty_typelist : type",
+"nonempty_typelist : nonempty_typelist ',' type",
+"name : NAME",
+"name : BLOCKNAME",
+"name : TYPENAME",
+"name : NAME_OR_INT",
+"name_not_typename : NAME",
+"name_not_typename : BLOCKNAME",
+};
+#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 914 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+
+/* 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 *) xrealloc (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.");
+}
+#line 1706 "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 3:
+#line 211 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type(yyvsp[0].tval);
+ write_exp_elt_opcode(OP_TYPE);}
+break;
+case 5:
+#line 219 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_COMMA); }
+break;
+case 6:
+#line 224 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (UNOP_IND); }
+break;
+case 7:
+#line 227 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (UNOP_ADDR); }
+break;
+case 8:
+#line 230 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (UNOP_NEG); }
+break;
+case 9:
+#line 234 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+break;
+case 10:
+#line 238 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (UNOP_COMPLEMENT); }
+break;
+case 11:
+#line 242 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (UNOP_PREINCREMENT); }
+break;
+case 12:
+#line 246 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (UNOP_PREDECREMENT); }
+break;
+case 13:
+#line 250 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (UNOP_POSTINCREMENT); }
+break;
+case 14:
+#line 254 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (UNOP_POSTDECREMENT); }
+break;
+case 15:
+#line 258 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (UNOP_SIZEOF); }
+break;
+case 16:
+#line 262 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (STRUCTOP_PTR);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (STRUCTOP_PTR); }
+break;
+case 17:
+#line 268 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ /* 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); }
+break;
+case 18:
+#line 275 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (STRUCTOP_MPTR); }
+break;
+case 19:
+#line 279 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (STRUCTOP_STRUCT); }
+break;
+case 20:
+#line 285 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ /* 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); }
+break;
+case 21:
+#line 293 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (STRUCTOP_MEMBER); }
+break;
+case 22:
+#line 297 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+break;
+case 23:
+#line 303 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ start_arglist (); }
+break;
+case 24:
+#line 305 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (OP_FUNCALL); }
+break;
+case 25:
+#line 311 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ start_arglist (); }
+break;
+case 27:
+#line 318 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ arglist_len = 1; }
+break;
+case 28:
+#line 322 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ arglist_len++; }
+break;
+case 29:
+#line 326 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.lval = end_arglist () - 1; }
+break;
+case 30:
+#line 329 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (OP_ARRAY);
+ write_exp_elt_longcst ((LONGEST) 0);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+ write_exp_elt_opcode (OP_ARRAY); }
+break;
+case 31:
+#line 336 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_elt_type (yyvsp[-2].tval);
+ write_exp_elt_opcode (UNOP_MEMVAL); }
+break;
+case 32:
+#line 342 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (yyvsp[-2].tval);
+ write_exp_elt_opcode (UNOP_CAST); }
+break;
+case 33:
+#line 348 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ }
+break;
+case 34:
+#line 354 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_REPEAT); }
+break;
+case 35:
+#line 358 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_MUL); }
+break;
+case 36:
+#line 362 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_DIV); }
+break;
+case 37:
+#line 366 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_REM); }
+break;
+case 38:
+#line 370 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_ADD); }
+break;
+case 39:
+#line 374 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_SUB); }
+break;
+case 40:
+#line 378 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_LSH); }
+break;
+case 41:
+#line 382 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_RSH); }
+break;
+case 42:
+#line 386 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_EQUAL); }
+break;
+case 43:
+#line 390 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_NOTEQUAL); }
+break;
+case 44:
+#line 394 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_LEQ); }
+break;
+case 45:
+#line 398 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_GEQ); }
+break;
+case 46:
+#line 402 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_LESS); }
+break;
+case 47:
+#line 406 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_GTR); }
+break;
+case 48:
+#line 410 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_BITWISE_AND); }
+break;
+case 49:
+#line 414 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+break;
+case 50:
+#line 418 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+break;
+case 51:
+#line 422 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+break;
+case 52:
+#line 426 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+break;
+case 53:
+#line 430 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (TERNOP_COND); }
+break;
+case 54:
+#line 434 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_ASSIGN); }
+break;
+case 55:
+#line 438 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY);
+ write_exp_elt_opcode (yyvsp[-1].opcode);
+ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); }
+break;
+case 56:
+#line 444 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (yyvsp[0].typed_val.type);
+ write_exp_elt_longcst ((LONGEST)(yyvsp[0].typed_val.val));
+ write_exp_elt_opcode (OP_LONG); }
+break;
+case 57:
+#line 451 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ YYSTYPE val;
+ parse_number (yyvsp[0].ssym.stoken.ptr, yyvsp[0].ssym.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);
+ }
+break;
+case 58:
+#line 462 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (OP_DOUBLE);
+ write_exp_elt_type (builtin_type_double);
+ write_exp_elt_dblcst (yyvsp[0].dval);
+ write_exp_elt_opcode (OP_DOUBLE); }
+break;
+case 60:
+#line 472 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (OP_LAST);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+ write_exp_elt_opcode (OP_LAST); }
+break;
+case 61:
+#line 478 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (OP_REGISTER);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+ write_exp_elt_opcode (OP_REGISTER); }
+break;
+case 62:
+#line 484 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (OP_INTERNALVAR);
+ write_exp_elt_intern (yyvsp[0].ivar);
+ write_exp_elt_opcode (OP_INTERNALVAR); }
+break;
+case 63:
+#line 490 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST) TYPE_LENGTH (yyvsp[-1].tval));
+ write_exp_elt_opcode (OP_LONG); }
+break;
+case 64:
+#line 497 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ /* 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 = yyvsp[0].sval.ptr; int count = yyvsp[0].sval.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) (yyvsp[0].sval.length));
+ write_exp_elt_opcode (OP_ARRAY); }
+break;
+case 65:
+#line 522 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ write_exp_elt_opcode (OP_THIS);
+ write_exp_elt_opcode (OP_THIS); }
+break;
+case 66:
+#line 529 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{
+ if (yyvsp[0].ssym.sym != 0)
+ yyval.bval = SYMBOL_BLOCK_VALUE (yyvsp[0].ssym.sym);
+ else
+ {
+ struct symtab *tem =
+ lookup_symtab (copy_name (yyvsp[0].ssym.stoken));
+ if (tem)
+ yyval.bval = BLOCKVECTOR_BLOCK
+ (BLOCKVECTOR (tem), STATIC_BLOCK);
+ else
+ error ("No file or function \"%s\".",
+ copy_name (yyvsp[0].ssym.stoken));
+ }
+ }
+break;
+case 67:
+#line 547 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ struct symbol *tem
+ = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
+ if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
+ error ("No function \"%s\" in specified context.",
+ copy_name (yyvsp[0].sval));
+ yyval.bval = SYMBOL_BLOCK_VALUE (tem); }
+break;
+case 68:
+#line 558 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ struct symbol *sym;
+ sym = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval,
+ VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym == 0)
+ error ("No symbol \"%s\" in specified context.",
+ copy_name (yyvsp[0].sval));
+
+ 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); }
+break;
+case 69:
+#line 574 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{
+ struct type *type = yyvsp[-2].tval;
+ 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 (yyvsp[0].sval);
+ write_exp_elt_opcode (OP_SCOPE);
+ }
+break;
+case 70:
+#line 587 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{
+ struct type *type = yyvsp[-3].tval;
+ 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), yyvsp[0].sval.ptr))
+ error ("invalid destructor `%s::~%s'",
+ type_name_no_tag (type), yyvsp[0].sval.ptr);
+
+ tmp_token.ptr = (char*) alloca (yyvsp[0].sval.length + 2);
+ tmp_token.length = yyvsp[0].sval.length + 1;
+ tmp_token.ptr[0] = '~';
+ memcpy (tmp_token.ptr+1, yyvsp[0].sval.ptr, yyvsp[0].sval.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);
+ }
+break;
+case 72:
+#line 613 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{
+ char *name = copy_name (yyvsp[0].sval);
+ 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);
+ }
+break;
+case 73:
+#line 658 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ struct symbol *sym = yyvsp[0].ssym.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 (yyvsp[0].ssym.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 (yyvsp[0].ssym.stoken);
+ write_exp_elt_opcode (STRUCTOP_PTR);
+ }
+ else
+ {
+ struct minimal_symbol *msymbol;
+ register char *arg = copy_name (yyvsp[0].ssym.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 (yyvsp[0].ssym.stoken));
+ }
+ }
+break;
+case 77:
+#line 737 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = follow_types (yyvsp[-1].tval); }
+break;
+case 78:
+#line 739 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = follow_types (yyvsp[-2].tval); }
+break;
+case 79:
+#line 741 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = follow_types (yyvsp[-2].tval); }
+break;
+case 80:
+#line 745 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ push_type (tp_pointer); yyval.voidval = 0; }
+break;
+case 81:
+#line 747 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ push_type (tp_pointer); yyval.voidval = yyvsp[0].voidval; }
+break;
+case 82:
+#line 749 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ push_type (tp_reference); yyval.voidval = 0; }
+break;
+case 83:
+#line 751 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ push_type (tp_reference); yyval.voidval = yyvsp[0].voidval; }
+break;
+case 85:
+#line 756 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.voidval = yyvsp[-1].voidval; }
+break;
+case 86:
+#line 758 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{
+ push_type_int (yyvsp[0].lval);
+ push_type (tp_array);
+ }
+break;
+case 87:
+#line 763 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{
+ push_type_int (yyvsp[0].lval);
+ push_type (tp_array);
+ yyval.voidval = 0;
+ }
+break;
+case 88:
+#line 773 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ push_type (tp_function); }
+break;
+case 89:
+#line 775 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ push_type (tp_function); }
+break;
+case 90:
+#line 779 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.lval = -1; }
+break;
+case 91:
+#line 781 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.lval = yyvsp[-1].typed_val.val; }
+break;
+case 92:
+#line 785 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 93:
+#line 787 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ free ((PTR)yyvsp[-1].tvec); yyval.voidval = 0; }
+break;
+case 95:
+#line 794 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = lookup_member_type (builtin_type_int, yyvsp[-2].tval); }
+break;
+case 96:
+#line 796 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = lookup_member_type (yyvsp[-5].tval, yyvsp[-3].tval); }
+break;
+case 97:
+#line 798 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = lookup_member_type
+ (lookup_function_type (yyvsp[-7].tval), yyvsp[-5].tval); }
+break;
+case 98:
+#line 801 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = lookup_member_type
+ (lookup_function_type (yyvsp[-8].tval), yyvsp[-6].tval);
+ free ((PTR)yyvsp[-1].tvec); }
+break;
+case 99:
+#line 808 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = yyvsp[0].tsym.type; }
+break;
+case 100:
+#line 810 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = builtin_type_int; }
+break;
+case 101:
+#line 812 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = builtin_type_long; }
+break;
+case 102:
+#line 814 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = builtin_type_short; }
+break;
+case 103:
+#line 816 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = builtin_type_long; }
+break;
+case 104:
+#line 818 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = builtin_type_unsigned_long; }
+break;
+case 105:
+#line 820 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = builtin_type_long_long; }
+break;
+case 106:
+#line 822 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = builtin_type_long_long; }
+break;
+case 107:
+#line 824 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = builtin_type_unsigned_long_long; }
+break;
+case 108:
+#line 826 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = builtin_type_unsigned_long_long; }
+break;
+case 109:
+#line 828 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = builtin_type_short; }
+break;
+case 110:
+#line 830 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = builtin_type_unsigned_short; }
+break;
+case 111:
+#line 832 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = lookup_struct (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+break;
+case 112:
+#line 835 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = lookup_struct (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+break;
+case 113:
+#line 838 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = lookup_union (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+break;
+case 114:
+#line 841 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = lookup_enum (copy_name (yyvsp[0].sval),
+ expression_context_block); }
+break;
+case 115:
+#line 844 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = lookup_unsigned_typename (TYPE_NAME(yyvsp[0].tsym.type)); }
+break;
+case 116:
+#line 846 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = builtin_type_unsigned_int; }
+break;
+case 117:
+#line 848 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = lookup_signed_typename (TYPE_NAME(yyvsp[0].tsym.type)); }
+break;
+case 118:
+#line 850 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = builtin_type_int; }
+break;
+case 119:
+#line 852 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = lookup_template_type(copy_name(yyvsp[-3].sval), yyvsp[-1].tval,
+ expression_context_block);
+ }
+break;
+case 120:
+#line 858 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = yyvsp[0].tval; }
+break;
+case 121:
+#line 859 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tval = yyvsp[0].tval; }
+break;
+case 123:
+#line 864 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{
+ yyval.tsym.stoken.ptr = "int";
+ yyval.tsym.stoken.length = 3;
+ yyval.tsym.type = builtin_type_int;
+ }
+break;
+case 124:
+#line 870 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{
+ yyval.tsym.stoken.ptr = "long";
+ yyval.tsym.stoken.length = 4;
+ yyval.tsym.type = builtin_type_long;
+ }
+break;
+case 125:
+#line 876 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{
+ yyval.tsym.stoken.ptr = "short";
+ yyval.tsym.stoken.length = 5;
+ yyval.tsym.type = builtin_type_short;
+ }
+break;
+case 126:
+#line 885 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.tvec = (struct type **) xmalloc (sizeof (struct type *) * 2);
+ yyval.ivec[0] = 1; /* Number of types in vector */
+ yyval.tvec[1] = yyvsp[0].tval;
+ }
+break;
+case 127:
+#line 890 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ int len = sizeof (struct type *) * (++(yyvsp[-2].ivec[0]) + 1);
+ yyval.tvec = (struct type **) xrealloc ((char *) yyvsp[-2].tvec, len);
+ yyval.tvec[yyval.ivec[0]] = yyvsp[0].tval;
+ }
+break;
+case 128:
+#line 896 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.sval = yyvsp[0].ssym.stoken; }
+break;
+case 129:
+#line 897 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.sval = yyvsp[0].ssym.stoken; }
+break;
+case 130:
+#line 898 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.sval = yyvsp[0].tsym.stoken; }
+break;
+case 131:
+#line 899 "/usr/src/gnu/usr.bin/gdb/gdb/c-exp.y"
+{ yyval.sval = yyvsp[0].ssym.stoken; }
+break;
+#line 2593 "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/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..ea07959
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-lang.c
@@ -0,0 +1,447 @@
+/* C language support routines 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. */
+
+#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;
+ 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;
+ 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)
+ 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 ("\"\"", 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;
+ }
+ 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,
+ TYPE_FLAG_SIGNED, "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,
+ TYPE_FLAG_SIGNED, "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,
+ TYPE_FLAG_SIGNED, "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,
+ TYPE_FLAG_SIGNED, "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,
+ TYPE_FLAG_SIGNED, "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 */
+ &BUILTIN_TYPE_LONGEST, /* longest signed integral type */
+ &BUILTIN_TYPE_UNSIGNED_LONGEST,/* longest unsigned integral type */
+ &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 */
+ &BUILTIN_TYPE_LONGEST, /* longest signed integral type */
+ &BUILTIN_TYPE_UNSIGNED_LONGEST,/* longest unsigned integral type */
+ &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);
+}
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..4c343a9
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-lang.h
@@ -0,0 +1,31 @@
+/* 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. */
+
+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 *, FILE *, int, int));
+
+extern int
+c_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, int, int,
+ 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..fa4035b
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-typeprint.c
@@ -0,0 +1,797 @@
+/* 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>
+
+extern int demangle; /* whether to print C++ syms raw or source-form */
+
+static void
+c_type_print_args PARAMS ((struct type *, FILE *));
+
+static void
+c_type_print_varspec_suffix PARAMS ((struct type *, FILE *, int, int, int));
+
+static void
+cp_type_print_derivation_info PARAMS ((FILE *, struct type *));
+
+void
+c_type_print_varspec_prefix PARAMS ((struct type *, FILE *, int, int));
+
+void
+c_type_print_base PARAMS ((struct type *, 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;
+ 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;
+ 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;
+ 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)
+ 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;
+ 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 (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;
+ 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;
+ 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:
+ c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
+ passed_a_ptr, 0);
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ if (!demangled_args)
+ 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 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 zero 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 negative means the same things as SHOW zero. The difference is that
+ zero is used for printing structure elements and -1 is used for the
+ "whatis" command. But I don't see any need to distinguish.
+
+ 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;
+ 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;
+ }
+
+ 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)
+ {
+ check_stub_type (type);
+
+ 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 (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)
+ {
+ 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..bcf0a28
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/c-valprint.c
@@ -0,0 +1,416 @@
+/* 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 "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 int demangle; /* whether to print C++ syms raw or src-form */
+
+extern void
+cp_print_class_member PARAMS ((char *, struct type *, FILE *, char *));
+
+extern void
+cp_print_class_method PARAMS ((char *, struct type *, FILE *));
+
+extern void
+cp_print_value_fields PARAMS ((struct type *, char *, 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 *, FILE *, int, int));
+
+extern void
+cp_type_print_method_args PARAMS ((struct type **, char *, char *, int,
+ 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;
+ 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
+ && (format == 0 || format == 's'))
+ {
+ 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 (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')
+ {
+ fprintf_filtered (stream, "0x%lx", (unsigned long)addr);
+ }
+
+ /* 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 (vtblprint)
+ {
+ value vt_val;
+ struct symbol *wsym = (struct symbol *)NULL;
+ struct type *wtype;
+ struct symtab *s;
+ struct block *block = (struct block *)NULL;
+ int is_this_fld;
+
+
+ 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, plus one for the
+ terminating null if we have "reached the end". */
+ return (i + (print_max && i != print_max));
+ }
+ 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, "@0x%lx",
+ unpack_long (builtin_type_int, valaddr));
+ if (deref_ref)
+ fputs_filtered (": ", stream);
+ }
+ /* De-reference the reference. */
+ if (deref_ref)
+ {
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_UNDEF)
+ {
+ value 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_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_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_RANGE:
+ /* FIXME, we should not ever have to print one of these yet. */
+ fprintf_filtered (stream, "<range 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));
+ }
+ fflush (stream);
+ return (0);
+}
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.tab.c b/gnu/usr.bin/gdb/gdb/ch-exp.tab.c
new file mode 100644
index 0000000..7adab65
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-exp.tab.c
@@ -0,0 +1,2854 @@
+#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 yyparse ch_parse
+#define yylex ch_lex
+#define yyerror ch_error
+#define yychar ch_char
+#define yyval ch_val
+#define yylval ch_lval
+#define yydebug ch_debug
+#define yynerrs ch_nerrs
+#define yyerrflag ch_errflag
+#define yyss ch_ss
+#define yyssp ch_ssp
+#define yyvs ch_vs
+#define yyvsp ch_vsp
+#define yylhs ch_lhs
+#define yylen ch_len
+#define yydefred ch_defred
+#define yydgoto ch_dgoto
+#define yysindex ch_sindex
+#define yyrindex ch_rindex
+#define yygindex ch_gindex
+#define yytable ch_table
+#define yycheck ch_check
+#define yyname ch_name
+#define yyrule ch_rule
+#define YYPREFIX "ch_"
+#line 55 "./ch-exp.y"
+
+#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 *));
+
+#line 120 "./ch-exp.y"
+typedef 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;
+ } YYSTYPE;
+#line 119 "y.tab.c"
+#define FIXME_01 257
+#define FIXME_02 258
+#define FIXME_03 259
+#define FIXME_04 260
+#define FIXME_05 261
+#define FIXME_06 262
+#define FIXME_07 263
+#define FIXME_08 264
+#define FIXME_09 265
+#define FIXME_10 266
+#define FIXME_11 267
+#define FIXME_12 268
+#define FIXME_13 269
+#define FIXME_14 270
+#define FIXME_15 271
+#define FIXME_16 272
+#define FIXME_17 273
+#define FIXME_18 274
+#define FIXME_19 275
+#define FIXME_20 276
+#define FIXME_21 277
+#define FIXME_22 278
+#define FIXME_24 279
+#define FIXME_25 280
+#define FIXME_26 281
+#define FIXME_27 282
+#define FIXME_28 283
+#define FIXME_29 284
+#define FIXME_30 285
+#define INTEGER_LITERAL 286
+#define BOOLEAN_LITERAL 287
+#define CHARACTER_LITERAL 288
+#define FLOAT_LITERAL 289
+#define GENERAL_PROCEDURE_NAME 290
+#define LOCATION_NAME 291
+#define SET_LITERAL 292
+#define EMPTINESS_LITERAL 293
+#define CHARACTER_STRING_LITERAL 294
+#define BIT_STRING_LITERAL 295
+#define TYPENAME 296
+#define FIELD_NAME 297
+#define CASE 298
+#define OF 299
+#define ESAC 300
+#define LOGIOR 301
+#define ORIF 302
+#define LOGXOR 303
+#define LOGAND 304
+#define ANDIF 305
+#define NOTEQUAL 306
+#define GTR 307
+#define LEQ 308
+#define IN 309
+#define SLASH_SLASH 310
+#define MOD 311
+#define REM 312
+#define NOT 313
+#define POINTER 314
+#define RECEIVE 315
+#define UP 316
+#define IF 317
+#define THEN 318
+#define ELSE 319
+#define FI 320
+#define ELSIF 321
+#define ILLEGAL_TOKEN 322
+#define NUM 323
+#define PRED 324
+#define SUCC 325
+#define ABS 326
+#define CARD 327
+#define MAX_TOKEN 328
+#define MIN_TOKEN 329
+#define SIZE 330
+#define UPPER 331
+#define LOWER 332
+#define LENGTH 333
+#define GDB_REGNAME 334
+#define GDB_LAST 335
+#define GDB_VARIABLE 336
+#define GDB_ASSIGNMENT 337
+#define YYERRCODE 256
+short ch_lhs[] = { -1,
+ 0, 0, 20, 20, 21, 1, 1, 2, 2, 2,
+ 2, 2, 45, 45, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 4,
+ 5, 5, 5, 5, 5, 6, 6, 6, 6, 6,
+ 6, 6, 6, 7, 8, 9, 9, 62, 10, 11,
+ 11, 12, 13, 14, 15, 17, 18, 19, 22, 22,
+ 22, 23, 23, 24, 25, 25, 26, 27, 28, 28,
+ 28, 28, 29, 29, 29, 30, 30, 30, 30, 30,
+ 30, 30, 30, 31, 31, 31, 31, 32, 32, 32,
+ 32, 32, 33, 33, 33, 33, 34, 34, 34, 60,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 49, 49, 49, 49, 61, 50, 50, 51,
+ 44, 52, 53, 54, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 46, 47, 48, 55, 56, 57, 58,
+ 59,
+};
+short ch_len[] = { 2,
+ 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,
+ 1, 1, 1, 3, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 4, 6, 6, 0, 5, 6,
+ 6, 2, 2, 1, 1, 1, 1, 3, 1, 1,
+ 1, 5, 9, 2, 2, 4, 1, 4, 1, 3,
+ 3, 3, 1, 3, 3, 1, 3, 3, 3, 3,
+ 3, 3, 3, 1, 3, 3, 3, 1, 3, 3,
+ 3, 3, 1, 2, 2, 2, 2, 2, 1, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 1, 4, 4, 4, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1,
+};
+short ch_defred[] = { 0,
+ 5, 12, 44, 54, 56, 57, 125, 126, 127, 128,
+ 129, 36, 37, 38, 39, 35, 8, 40, 41, 42,
+ 43, 117, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 10, 9, 11, 0, 0, 6, 0, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 55,
+ 27, 28, 0, 1, 4, 3, 61, 0, 0, 0,
+ 0, 0, 88, 93, 31, 32, 33, 34, 0, 0,
+ 60, 0, 138, 0, 30, 29, 94, 0, 95, 0,
+ 0, 141, 98, 0, 137, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 52, 7,
+ 96, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 53, 0, 58, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 122, 123, 124, 0, 0, 0,
+ 0, 0, 0, 118, 0, 0, 0, 120, 0, 100,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 89, 90, 91, 92, 130,
+ 131, 0, 0, 134, 136, 0, 0, 0, 140, 0,
+ 0, 139, 64, 0, 0, 0, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 0, 0, 0, 110, 111,
+ 112, 45, 0, 0, 0, 0, 13, 0, 0, 0,
+ 65, 0, 62, 0, 0, 0, 133, 0, 132, 0,
+ 135, 0, 0, 49, 0, 0, 67, 0, 0, 114,
+ 115, 116, 47, 46, 50, 51, 14, 0, 68, 66,
+ 0, 63,
+};
+short ch_dgoto[] = { 44,
+ 85, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 137, 196, 238, 190, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78, 79, 182,
+ 183, 230, 228, 80, 218, 186, 232, 187, 149, 155,
+ 159, 150, 151, 152, 96, 84, 193, 191, 93, 81,
+ 88, 188,
+};
+short ch_sindex[] = { 457,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -262, 879, 879, 893, -215, 622, -258, 50,
+ 51, 52, 53, 56, 57, 58, 67, 72, 73, 75,
+ 0, 0, 0, 0, -221, 0, -293, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, -261, 0, 0, 0, 0, -248, -275, -44,
+ -30, -33, 0, 0, 0, 0, 0, 0, 88, 91,
+ 0, 92, 0, -165, 0, 0, 0, 92, 0, 0,
+ -293, 0, 0, 94, 0, -181, 622, 622, 622, 622,
+ 622, 622, 622, 636, 622, 622, 622, 457, 0, 0,
+ 0, 797, 797, 797, 797, 797, 797, 797, 797, 797,
+ 797, 797, 797, 797, 797, 797, 797, 797, 797, 797,
+ -233, -270, 0, -137, 0, -132, -272, 112, 118, 119,
+ 120, 121, 122, 128, 0, 0, 0, 129, 130, 132,
+ 141, 143, 92, 0, 144, 92, 146, 0, 149, 0,
+ -275, -275, -275, -44, -44, -30, -30, -30, -30, -30,
+ -30, -30, -33, -33, -33, 0, 0, 0, 0, 0,
+ 0, -39, 115, 0, 0, 126, -120, 622, 0, 106,
+ 142, 0, 0, -132, -258, -110, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 622, 622, 622, 0, 0,
+ 0, 0, -64, -61, -63, -64, 0, -34, -103, 622,
+ 0, -181, 0, 174, 181, -22, 0, 182, 0, 184,
+ 0, 192, 193, 0, 622, 622, 0, 177, -272, 0,
+ 0, 0, 0, 0, 0, 0, 0, 150, 0, 0,
+ -55, 0,
+};
+short ch_rindex[] = { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 82, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 24, 0, 0, 0, 0, 506, 255, 191,
+ 145, 95, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 237, 0, 0, 0, 0, 0, 0, 0, 59,
+ 204, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 714, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, -40, 0, 0,
+ 0, 0, 205, 0, 0, 206, 0, 0, 0, 0,
+ 567, 573, 577, 531, 554, 168, 180, 208, 231, 500,
+ 522, 545, 105, 133, 158, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+};
+short ch_gindex[] = { 0,
+ 1230, 0, -23, 0, 0, 185, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 26, 148,
+ 0, 1162, 0, 31, 15, 22, 0, 0, -56, -104,
+ -45, -37, -92, 55, 0, 0, 0, 0, 0, 0,
+ 0, 0, 43, 0, 63, 0, 0, 0, 0, 154,
+ 0, 0, 0, 0, 71, 0, 87, 0, 0, 0,
+ 5, 0,
+};
+#define YYTABLESIZE 1466
+short ch_table[] = { 30,
+ 30, 212, 91, 109, 82, 184, 234, 185, 127, 235,
+ 164, 165, 124, 128, 125, 121, 117, 119, 242, 83,
+ 110, 235, 95, 29, 12, 13, 14, 15, 115, 116,
+ 18, 19, 20, 21, 176, 177, 178, 179, 180, 181,
+ 30, 30, 30, 30, 30, 30, 194, 30, 195, 86,
+ 86, 86, 112, 113, 114, 161, 162, 163, 97, 30,
+ 30, 30, 30, 29, 29, 29, 29, 29, 29, 92,
+ 29, 166, 167, 168, 169, 170, 171, 172, 87, 89,
+ 91, 99, 29, 29, 29, 29, 173, 174, 175, 97,
+ 98, 99, 100, 30, 84, 101, 102, 103, 30, 97,
+ 97, 97, 97, 97, 85, 97, 104, 133, 153, 156,
+ 156, 105, 106, 133, 107, 108, 29, 97, 97, 97,
+ 97, 121, 99, 99, 99, 99, 99, 131, 99, 86,
+ 132, 28, 86, 134, 135, 84, 136, 84, 84, 84,
+ 99, 99, 99, 99, 76, 85, 189, 85, 85, 85,
+ 192, 97, 197, 84, 84, 84, 84, 87, 198, 199,
+ 200, 201, 202, 85, 85, 85, 85, 77, 203, 204,
+ 205, 206, 214, 86, 99, 86, 86, 86, 133, 78,
+ 207, 133, 208, 215, 209, 76, 210, 84, 76, 211,
+ 73, 86, 86, 86, 86, 216, 219, 85, 87, 220,
+ 87, 87, 87, 76, 76, 76, 76, 79, 77, 223,
+ 227, 77, 229, 231, 240, 236, 87, 87, 87, 87,
+ 78, 241, 243, 78, 244, 86, 77, 77, 77, 77,
+ 80, 73, 245, 246, 73, 249, 2, 76, 78, 78,
+ 78, 78, 251, 121, 252, 113, 119, 111, 79, 73,
+ 87, 79, 239, 250, 69, 160, 30, 248, 233, 157,
+ 77, 118, 120, 122, 123, 222, 79, 79, 79, 79,
+ 226, 80, 78, 30, 80, 0, 213, 129, 130, 126,
+ 221, 0, 0, 73, 0, 0, 0, 0, 0, 80,
+ 80, 80, 80, 0, 0, 69, 0, 30, 69, 0,
+ 79, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 69, 30, 0, 0, 0, 0, 0,
+ 29, 0, 0, 80, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 0, 29, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 69, 0, 0,
+ 0, 0, 0, 0, 0, 30, 0, 0, 0, 97,
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+ 97, 0, 30, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 0, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 85, 85, 85, 85, 85,
+ 85, 85, 85, 85, 85, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 0, 0, 76, 76, 76, 76, 76,
+ 76, 76, 76, 76, 0, 0, 0, 0, 87, 87,
+ 87, 87, 87, 87, 87, 87, 87, 87, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 0, 0, 0,
+ 78, 78, 78, 78, 78, 78, 78, 78, 78, 0,
+ 0, 73, 73, 73, 73, 73, 28, 0, 0, 81,
+ 0, 24, 0, 0, 0, 59, 0, 0, 79, 79,
+ 79, 79, 79, 79, 79, 79, 79, 0, 0, 0,
+ 0, 82, 0, 0, 0, 0, 0, 0, 0, 0,
+ 74, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+ 81, 0, 0, 81, 83, 0, 59, 0, 0, 59,
+ 0, 0, 0, 75, 0, 69, 69, 69, 81, 81,
+ 81, 81, 82, 0, 59, 82, 70, 0, 0, 0,
+ 0, 74, 71, 0, 74, 0, 72, 0, 0, 0,
+ 82, 82, 82, 82, 0, 83, 0, 0, 83, 74,
+ 0, 0, 81, 0, 75, 0, 0, 75, 59, 0,
+ 0, 0, 0, 83, 83, 83, 83, 70, 0, 0,
+ 70, 0, 75, 71, 82, 0, 71, 72, 0, 0,
+ 72, 0, 0, 74, 0, 70, 0, 0, 0, 0,
+ 0, 71, 0, 0, 0, 72, 0, 83, 0, 0,
+ 0, 0, 0, 0, 0, 0, 75, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 70,
+ 0, 28, 0, 0, 0, 71, 24, 0, 0, 72,
+ 0, 0, 0, 0, 0, 28, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 2, 3, 4, 5, 6,
+ 0, 0, 0, 7, 8, 9, 10, 11, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 48, 23, 0, 0, 0, 48, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 25,
+ 26, 27, 0, 29, 0, 0, 0, 0, 0, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 0, 0, 0, 0, 0, 0, 0,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 82, 82, 82, 82, 82, 82, 82, 82,
+ 82, 74, 74, 74, 74, 74, 28, 0, 0, 0,
+ 0, 24, 0, 0, 0, 83, 83, 83, 83, 83,
+ 83, 83, 83, 83, 75, 75, 75, 75, 75, 0,
+ 0, 0, 0, 0, 0, 0, 0, 70, 70, 70,
+ 0, 0, 0, 71, 71, 71, 0, 72, 72, 72,
+ 2, 3, 4, 5, 6, 0, 0, 0, 7, 8,
+ 9, 10, 11, 0, 2, 3, 4, 5, 6, 145,
+ 146, 147, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 28, 23,
+ 0, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 28, 0, 25, 26, 27, 0, 29, 0,
+ 0, 0, 0, 0, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 48, 48, 48, 48, 48, 0, 0, 0,
+ 48, 48, 48, 48, 48, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+ 0, 48, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 48, 48, 48, 0,
+ 48, 0, 0, 0, 0, 0, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+ 0, 0, 0, 0, 0, 2, 3, 4, 5, 6,
+ 0, 0, 0, 7, 8, 9, 10, 11, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 25,
+ 26, 27, 0, 0, 0, 0, 0, 0, 0, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 0, 0, 0, 0, 2, 3, 4,
+ 5, 6, 0, 0, 0, 7, 8, 9, 10, 11,
+ 0, 2, 3, 4, 5, 6, 0, 0, 0, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 0, 0, 0, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 94,
+ 0, 0, 26, 27, 0, 0, 0, 0, 0, 0,
+ 0, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 42, 43, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 45,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 90, 0, 45, 138, 139,
+ 140, 141, 142, 143, 144, 0, 154, 154, 158, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 45, 45, 45, 45,
+ 45, 45, 45, 148, 45, 45, 45, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 217,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 224, 225, 217,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 237, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 247, 237, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 45, 45, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 45,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 45, 45,
+};
+short ch_check[] = { 40,
+ 0, 41, 26, 297, 0, 276, 41, 278, 42, 44,
+ 115, 116, 43, 47, 45, 60, 61, 62, 41, 282,
+ 314, 44, 281, 0, 286, 287, 288, 289, 304, 305,
+ 292, 293, 294, 295, 127, 128, 129, 130, 272, 273,
+ 40, 41, 42, 43, 44, 45, 319, 47, 321, 24,
+ 25, 26, 301, 302, 303, 112, 113, 114, 0, 59,
+ 60, 61, 62, 40, 41, 42, 43, 44, 45, 285,
+ 47, 117, 118, 119, 120, 121, 122, 123, 24, 25,
+ 104, 0, 59, 60, 61, 62, 124, 125, 126, 40,
+ 40, 40, 40, 93, 0, 40, 40, 40, 40, 41,
+ 42, 43, 44, 45, 0, 47, 40, 82, 104, 105,
+ 106, 40, 40, 88, 40, 337, 93, 59, 60, 61,
+ 62, 40, 41, 42, 43, 44, 45, 40, 47, 104,
+ 40, 40, 0, 299, 41, 41, 318, 43, 44, 45,
+ 59, 60, 61, 62, 0, 41, 284, 43, 44, 45,
+ 283, 93, 41, 59, 60, 61, 62, 0, 41, 41,
+ 41, 41, 41, 59, 60, 61, 62, 0, 41, 41,
+ 41, 40, 58, 41, 93, 43, 44, 45, 153, 0,
+ 40, 156, 40, 58, 41, 41, 41, 93, 44, 41,
+ 0, 59, 60, 61, 62, 316, 91, 93, 41, 58,
+ 43, 44, 45, 59, 60, 61, 62, 0, 41, 320,
+ 275, 44, 274, 277, 41, 319, 59, 60, 61, 62,
+ 41, 41, 41, 44, 41, 93, 59, 60, 61, 62,
+ 0, 41, 41, 41, 44, 59, 0, 93, 59, 60,
+ 61, 62, 93, 40, 300, 41, 41, 63, 41, 59,
+ 93, 44, 222, 239, 0, 108, 297, 236, 216, 106,
+ 93, 306, 307, 308, 309, 195, 59, 60, 61, 62,
+ 208, 41, 93, 314, 44, -1, 316, 311, 312, 310,
+ 194, -1, -1, 93, -1, -1, -1, -1, -1, 59,
+ 60, 61, 62, -1, -1, 41, -1, 297, 44, -1,
+ 93, 301, 302, 303, 304, 305, 306, 307, 308, 309,
+ 310, 311, 312, 59, 314, -1, -1, -1, -1, -1,
+ 297, -1, -1, 93, 301, 302, 303, 304, 305, 306,
+ 307, 308, 309, 310, 311, 312, -1, 314, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 93, -1, -1,
+ -1, -1, -1, -1, -1, 297, -1, -1, -1, 301,
+ 302, 303, 304, 305, 306, 307, 308, 309, 310, 311,
+ 312, -1, 314, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 301, 302, 303, 304, 305, 306, 307, 308,
+ 309, 310, 311, 312, -1, 301, 302, 303, 304, 305,
+ 306, 307, 308, 309, 310, 301, 302, 303, 304, 305,
+ 306, 307, 308, 309, 310, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 301, 302, 303, 304, 305, 306, 307,
+ 308, 309, 310, -1, -1, 301, 302, 303, 304, 305,
+ 306, 307, 308, 309, -1, -1, -1, -1, 301, 302,
+ 303, 304, 305, 306, 307, 308, 309, 310, 301, 302,
+ 303, 304, 305, 306, 307, 308, 309, -1, -1, -1,
+ 301, 302, 303, 304, 305, 306, 307, 308, 309, -1,
+ -1, 301, 302, 303, 304, 305, 40, -1, -1, 0,
+ -1, 45, -1, -1, -1, 0, -1, -1, 301, 302,
+ 303, 304, 305, 306, 307, 308, 309, -1, -1, -1,
+ -1, 0, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 301, 302, 303, 304, 305, 306, 307, 308, 309,
+ 41, -1, -1, 44, 0, -1, 41, -1, -1, 44,
+ -1, -1, -1, 0, -1, 301, 302, 303, 59, 60,
+ 61, 62, 41, -1, 59, 44, 0, -1, -1, -1,
+ -1, 41, 0, -1, 44, -1, 0, -1, -1, -1,
+ 59, 60, 61, 62, -1, 41, -1, -1, 44, 59,
+ -1, -1, 93, -1, 41, -1, -1, 44, 93, -1,
+ -1, -1, -1, 59, 60, 61, 62, 41, -1, -1,
+ 44, -1, 59, 41, 93, -1, 44, 41, -1, -1,
+ 44, -1, -1, 93, -1, 59, -1, -1, -1, -1,
+ -1, 59, -1, -1, -1, 59, -1, 93, -1, -1,
+ -1, -1, -1, -1, -1, -1, 93, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 93,
+ -1, 40, -1, -1, -1, 93, 45, -1, -1, 93,
+ -1, -1, -1, -1, -1, 40, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -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, 259, 260, 261, 262, 263,
+ -1, -1, -1, 267, 268, 269, 270, 271, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 286, 287, 288, 289, 290, 291, 292, 293,
+ 294, 295, 296, 40, 298, -1, -1, -1, 45, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 313,
+ 314, 315, -1, 317, -1, -1, -1, -1, -1, 323,
+ 324, 325, 326, 327, 328, 329, 330, 331, 332, 333,
+ 334, 335, 336, -1, -1, -1, -1, -1, -1, -1,
+ 301, 302, 303, 304, 305, 306, 307, 308, 309, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 301, 302, 303, 304, 305, 306, 307, 308,
+ 309, 301, 302, 303, 304, 305, 40, -1, -1, -1,
+ -1, 45, -1, -1, -1, 301, 302, 303, 304, 305,
+ 306, 307, 308, 309, 301, 302, 303, 304, 305, -1,
+ -1, -1, -1, -1, -1, -1, -1, 301, 302, 303,
+ -1, -1, -1, 301, 302, 303, -1, 301, 302, 303,
+ 259, 260, 261, 262, 263, -1, -1, -1, 267, 268,
+ 269, 270, 271, -1, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 286, 287, 288,
+ 289, 290, 291, 292, 293, 294, 295, 296, 40, 298,
+ -1, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 40, -1, 313, 314, 315, -1, 317, -1,
+ -1, -1, -1, -1, 323, 324, 325, 326, 327, 328,
+ 329, 330, 331, 332, 333, 334, 335, 336, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 259, 260, 261, 262, 263, -1, -1, -1,
+ 267, 268, 269, 270, 271, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 286,
+ 287, 288, 289, 290, 291, 292, 293, 294, 295, 296,
+ -1, 298, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 313, 314, 315, -1,
+ 317, -1, -1, -1, -1, -1, 323, 324, 325, 326,
+ 327, 328, 329, 330, 331, 332, 333, 334, 335, 336,
+ -1, -1, -1, -1, -1, 259, 260, 261, 262, 263,
+ -1, -1, -1, 267, 268, 269, 270, 271, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 286, 287, 288, 289, 290, 291, 292, 293,
+ 294, 295, 296, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 313,
+ 314, 315, -1, -1, -1, -1, -1, -1, -1, 323,
+ 324, 325, 326, 327, 328, 329, 330, 331, 332, 333,
+ 334, 335, 336, -1, -1, -1, -1, 259, 260, 261,
+ 262, 263, -1, -1, -1, 267, 268, 269, 270, 271,
+ -1, 259, 260, 261, 262, 263, -1, -1, -1, 267,
+ 268, 269, 270, 271, 286, 287, 288, 289, 290, 291,
+ 292, 293, 294, 295, 296, -1, -1, -1, 286, 287,
+ 288, 289, 290, 291, 292, 293, 294, 295, 296, 28,
+ -1, -1, 314, 315, -1, -1, -1, -1, -1, -1,
+ -1, 323, 324, 325, 326, 327, 328, 329, 330, 331,
+ 332, 333, 334, 335, 336, 323, 324, 325, 326, 327,
+ 328, 329, 330, 331, 332, 333, 334, 335, 336, 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, 26, -1, 28, 97, 98,
+ 99, 100, 101, 102, 103, -1, 105, 106, 107, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 97, 98, 99, 100,
+ 101, 102, 103, 104, 105, 106, 107, 108, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 188,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 206, 207, 208,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 220, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 235, 236, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 188, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 206, 207, 208, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 220,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 235, 236,
+};
+#define YYFINAL 44
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 337
+#if YYDEBUG
+char *ch_name[] = {
+"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,"FIXME_01","FIXME_02","FIXME_03","FIXME_04",
+"FIXME_05","FIXME_06","FIXME_07","FIXME_08","FIXME_09","FIXME_10","FIXME_11",
+"FIXME_12","FIXME_13","FIXME_14","FIXME_15","FIXME_16","FIXME_17","FIXME_18",
+"FIXME_19","FIXME_20","FIXME_21","FIXME_22","FIXME_24","FIXME_25","FIXME_26",
+"FIXME_27","FIXME_28","FIXME_29","FIXME_30","INTEGER_LITERAL","BOOLEAN_LITERAL",
+"CHARACTER_LITERAL","FLOAT_LITERAL","GENERAL_PROCEDURE_NAME","LOCATION_NAME",
+"SET_LITERAL","EMPTINESS_LITERAL","CHARACTER_STRING_LITERAL",
+"BIT_STRING_LITERAL","TYPENAME","FIELD_NAME","CASE","OF","ESAC","LOGIOR","ORIF",
+"LOGXOR","LOGAND","ANDIF","NOTEQUAL","GTR","LEQ","IN","SLASH_SLASH","MOD","REM",
+"NOT","POINTER","RECEIVE","UP","IF","THEN","ELSE","FI","ELSIF","ILLEGAL_TOKEN",
+"NUM","PRED","SUCC","ABS","CARD","MAX_TOKEN","MIN_TOKEN","SIZE","UPPER","LOWER",
+"LENGTH","GDB_REGNAME","GDB_LAST","GDB_VARIABLE","GDB_ASSIGNMENT",
+};
+char *ch_rule[] = {
+"$accept : start",
+"start : value",
+"start : mode_name",
+"value : expression",
+"value : undefined_value",
+"undefined_value : FIXME_01",
+"location : access_name",
+"location : primitive_value POINTER",
+"access_name : LOCATION_NAME",
+"access_name : GDB_LAST",
+"access_name : GDB_REGNAME",
+"access_name : GDB_VARIABLE",
+"access_name : FIXME_03",
+"expression_list : expression",
+"expression_list : expression_list ',' expression",
+"primitive_value : location_contents",
+"primitive_value : value_name",
+"primitive_value : literal",
+"primitive_value : tuple",
+"primitive_value : value_string_element",
+"primitive_value : value_string_slice",
+"primitive_value : value_array_element",
+"primitive_value : value_array_slice",
+"primitive_value : value_structure_field",
+"primitive_value : expression_conversion",
+"primitive_value : value_procedure_call",
+"primitive_value : value_built_in_routine_call",
+"primitive_value : start_expression",
+"primitive_value : zero_adic_operator",
+"primitive_value : parenthesised_expression",
+"location_contents : location",
+"value_name : synonym_name",
+"value_name : value_enumeration_name",
+"value_name : value_do_with_name",
+"value_name : value_receive_name",
+"value_name : GENERAL_PROCEDURE_NAME",
+"literal : INTEGER_LITERAL",
+"literal : BOOLEAN_LITERAL",
+"literal : CHARACTER_LITERAL",
+"literal : FLOAT_LITERAL",
+"literal : SET_LITERAL",
+"literal : EMPTINESS_LITERAL",
+"literal : CHARACTER_STRING_LITERAL",
+"literal : BIT_STRING_LITERAL",
+"tuple : FIXME_04",
+"value_string_element : string_primitive_value '(' start_element ')'",
+"value_string_slice : string_primitive_value '(' left_element ':' right_element ')'",
+"value_string_slice : string_primitive_value '(' start_element UP slice_size ')'",
+"$$1 :",
+"value_array_element : array_primitive_value '(' $$1 expression_list ')'",
+"value_array_slice : array_primitive_value '(' lower_element ':' upper_element ')'",
+"value_array_slice : array_primitive_value '(' first_element UP slice_size ')'",
+"value_structure_field : primitive_value FIELD_NAME",
+"expression_conversion : mode_name parenthesised_expression",
+"value_procedure_call : FIXME_05",
+"value_built_in_routine_call : chill_value_built_in_routine_call",
+"start_expression : FIXME_06",
+"zero_adic_operator : FIXME_07",
+"parenthesised_expression : '(' expression ')'",
+"expression : operand_0",
+"expression : single_assignment_action",
+"expression : conditional_expression",
+"conditional_expression : IF boolean_expression then_alternative else_alternative FI",
+"conditional_expression : CASE case_selector_list OF value_case_alternative '[' ELSE sub_expression ']' ESAC",
+"then_alternative : THEN subexpression",
+"else_alternative : ELSE subexpression",
+"else_alternative : ELSIF boolean_expression then_alternative else_alternative",
+"sub_expression : expression",
+"value_case_alternative : case_label_specification ':' sub_expression ';'",
+"operand_0 : operand_1",
+"operand_0 : operand_0 LOGIOR operand_1",
+"operand_0 : operand_0 ORIF operand_1",
+"operand_0 : operand_0 LOGXOR operand_1",
+"operand_1 : operand_2",
+"operand_1 : operand_1 LOGAND operand_2",
+"operand_1 : operand_1 ANDIF operand_2",
+"operand_2 : operand_3",
+"operand_2 : operand_2 '=' operand_3",
+"operand_2 : operand_2 NOTEQUAL operand_3",
+"operand_2 : operand_2 '>' operand_3",
+"operand_2 : operand_2 GTR operand_3",
+"operand_2 : operand_2 '<' operand_3",
+"operand_2 : operand_2 LEQ operand_3",
+"operand_2 : operand_2 IN operand_3",
+"operand_3 : operand_4",
+"operand_3 : operand_3 '+' operand_4",
+"operand_3 : operand_3 '-' operand_4",
+"operand_3 : operand_3 SLASH_SLASH operand_4",
+"operand_4 : operand_5",
+"operand_4 : operand_4 '*' operand_5",
+"operand_4 : operand_4 '/' operand_5",
+"operand_4 : operand_4 MOD operand_5",
+"operand_4 : operand_4 REM operand_5",
+"operand_5 : operand_6",
+"operand_5 : '-' operand_6",
+"operand_5 : NOT operand_6",
+"operand_5 : parenthesised_expression literal",
+"operand_6 : POINTER location",
+"operand_6 : RECEIVE buffer_location",
+"operand_6 : primitive_value",
+"single_assignment_action : location GDB_ASSIGNMENT value",
+"chill_value_built_in_routine_call : NUM '(' expression ')'",
+"chill_value_built_in_routine_call : PRED '(' expression ')'",
+"chill_value_built_in_routine_call : SUCC '(' expression ')'",
+"chill_value_built_in_routine_call : ABS '(' expression ')'",
+"chill_value_built_in_routine_call : CARD '(' expression ')'",
+"chill_value_built_in_routine_call : MAX_TOKEN '(' expression ')'",
+"chill_value_built_in_routine_call : MIN_TOKEN '(' expression ')'",
+"chill_value_built_in_routine_call : SIZE '(' location ')'",
+"chill_value_built_in_routine_call : SIZE '(' mode_argument ')'",
+"chill_value_built_in_routine_call : UPPER '(' upper_lower_argument ')'",
+"chill_value_built_in_routine_call : LOWER '(' upper_lower_argument ')'",
+"chill_value_built_in_routine_call : LENGTH '(' length_argument ')'",
+"mode_argument : mode_name",
+"mode_argument : array_mode_name '(' expression ')'",
+"mode_argument : string_mode_name '(' expression ')'",
+"mode_argument : variant_structure_mode_name '(' expression_list ')'",
+"mode_name : TYPENAME",
+"upper_lower_argument : expression",
+"upper_lower_argument : mode_name",
+"length_argument : expression",
+"array_primitive_value : primitive_value",
+"array_mode_name : FIXME_08",
+"string_mode_name : FIXME_09",
+"variant_structure_mode_name : FIXME_10",
+"synonym_name : FIXME_11",
+"value_enumeration_name : FIXME_12",
+"value_do_with_name : FIXME_13",
+"value_receive_name : FIXME_14",
+"string_primitive_value : FIXME_15",
+"start_element : FIXME_16",
+"left_element : FIXME_17",
+"right_element : FIXME_18",
+"slice_size : FIXME_19",
+"lower_element : FIXME_20",
+"upper_element : FIXME_21",
+"first_element : FIXME_22",
+"boolean_expression : FIXME_26",
+"case_selector_list : FIXME_27",
+"subexpression : FIXME_28",
+"case_label_specification : FIXME_29",
+"buffer_location : FIXME_30",
+};
+#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 994 "./ch-exp.y"
+
+/* 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 *) xmalloc (tempbufsize);
+ }
+ else
+ {
+ tempbuf = (char *) xrealloc (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");
+ }
+}
+#line 1836 "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 312 "./ch-exp.y"
+{ }
+break;
+case 2:
+#line 314 "./ch-exp.y"
+{ write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type(yyvsp[0].tsym.type);
+ write_exp_elt_opcode(OP_TYPE);}
+break;
+case 3:
+#line 320 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 4:
+#line 324 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 5:
+#line 330 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 7:
+#line 339 "./ch-exp.y"
+{
+ write_exp_elt_opcode (UNOP_IND);
+ }
+break;
+case 8:
+#line 347 "./ch-exp.y"
+{
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym (yyvsp[0].ssym.sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ }
+break;
+case 9:
+#line 354 "./ch-exp.y"
+{
+ write_exp_elt_opcode (OP_LAST);
+ write_exp_elt_longcst (yyvsp[0].lval);
+ write_exp_elt_opcode (OP_LAST);
+ }
+break;
+case 10:
+#line 360 "./ch-exp.y"
+{
+ write_exp_elt_opcode (OP_REGISTER);
+ write_exp_elt_longcst (yyvsp[0].lval);
+ write_exp_elt_opcode (OP_REGISTER);
+ }
+break;
+case 11:
+#line 366 "./ch-exp.y"
+{
+ write_exp_elt_opcode (OP_INTERNALVAR);
+ write_exp_elt_intern (yyvsp[0].ivar);
+ write_exp_elt_opcode (OP_INTERNALVAR);
+ }
+break;
+case 12:
+#line 372 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 13:
+#line 380 "./ch-exp.y"
+{
+ arglist_len = 1;
+ }
+break;
+case 14:
+#line 384 "./ch-exp.y"
+{
+ arglist_len++;
+ }
+break;
+case 15:
+#line 391 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 16:
+#line 395 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 17:
+#line 399 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 18:
+#line 403 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 19:
+#line 407 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 20:
+#line 411 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 21:
+#line 415 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 22:
+#line 419 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 23:
+#line 423 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 24:
+#line 427 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 25:
+#line 431 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 26:
+#line 435 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 27:
+#line 439 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 28:
+#line 443 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 29:
+#line 447 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 30:
+#line 455 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 31:
+#line 463 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 32:
+#line 467 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 33:
+#line 471 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 34:
+#line 475 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 35:
+#line 479 "./ch-exp.y"
+{
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym (yyvsp[0].ssym.sym);
+ write_exp_elt_opcode (OP_VAR_VALUE);
+ }
+break;
+case 36:
+#line 490 "./ch-exp.y"
+{
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (yyvsp[0].typed_val.type);
+ write_exp_elt_longcst ((LONGEST) (yyvsp[0].typed_val.val));
+ write_exp_elt_opcode (OP_LONG);
+ }
+break;
+case 37:
+#line 497 "./ch-exp.y"
+{
+ write_exp_elt_opcode (OP_BOOL);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval);
+ write_exp_elt_opcode (OP_BOOL);
+ }
+break;
+case 38:
+#line 503 "./ch-exp.y"
+{
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (yyvsp[0].typed_val.type);
+ write_exp_elt_longcst ((LONGEST) (yyvsp[0].typed_val.val));
+ write_exp_elt_opcode (OP_LONG);
+ }
+break;
+case 39:
+#line 510 "./ch-exp.y"
+{
+ write_exp_elt_opcode (OP_DOUBLE);
+ write_exp_elt_type (builtin_type_double);
+ write_exp_elt_dblcst (yyvsp[0].dval);
+ write_exp_elt_opcode (OP_DOUBLE);
+ }
+break;
+case 40:
+#line 517 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 41:
+#line 521 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 42:
+#line 525 "./ch-exp.y"
+{
+ write_exp_elt_opcode (OP_STRING);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (OP_STRING);
+ }
+break;
+case 43:
+#line 531 "./ch-exp.y"
+{
+ write_exp_elt_opcode (OP_BITSTRING);
+ write_exp_bitstring (yyvsp[0].sval);
+ write_exp_elt_opcode (OP_BITSTRING);
+ }
+break;
+case 44:
+#line 541 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 45:
+#line 550 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 46:
+#line 558 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 47:
+#line 562 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 48:
+#line 572 "./ch-exp.y"
+{ start_arglist (); }
+break;
+case 49:
+#line 574 "./ch-exp.y"
+{
+ write_exp_elt_opcode (MULTI_SUBSCRIPT);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (MULTI_SUBSCRIPT);
+ }
+break;
+case 50:
+#line 584 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 51:
+#line 588 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 52:
+#line 596 "./ch-exp.y"
+{ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ }
+break;
+case 53:
+#line 605 "./ch-exp.y"
+{
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (yyvsp[-1].tsym.type);
+ write_exp_elt_opcode (UNOP_CAST);
+ }
+break;
+case 54:
+#line 615 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 55:
+#line 623 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 56:
+#line 631 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 57:
+#line 639 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 58:
+#line 647 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 59:
+#line 655 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 60:
+#line 659 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 61:
+#line 663 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 62:
+#line 669 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 63:
+#line 673 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 64:
+#line 679 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 65:
+#line 685 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 66:
+#line 689 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 67:
+#line 695 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 68:
+#line 701 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 69:
+#line 709 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 70:
+#line 713 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_BITWISE_IOR);
+ }
+break;
+case 71:
+#line 717 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 72:
+#line 721 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_BITWISE_XOR);
+ }
+break;
+case 73:
+#line 729 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 74:
+#line 733 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_BITWISE_AND);
+ }
+break;
+case 75:
+#line 737 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 76:
+#line 745 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 77:
+#line 749 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_EQUAL);
+ }
+break;
+case 78:
+#line 753 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_NOTEQUAL);
+ }
+break;
+case 79:
+#line 757 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_GTR);
+ }
+break;
+case 80:
+#line 761 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_GEQ);
+ }
+break;
+case 81:
+#line 765 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_LESS);
+ }
+break;
+case 82:
+#line 769 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_LEQ);
+ }
+break;
+case 83:
+#line 773 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 84:
+#line 782 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 85:
+#line 786 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_ADD);
+ }
+break;
+case 86:
+#line 790 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_SUB);
+ }
+break;
+case 87:
+#line 794 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_CONCAT);
+ }
+break;
+case 88:
+#line 802 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 89:
+#line 806 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_MUL);
+ }
+break;
+case 90:
+#line 810 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_DIV);
+ }
+break;
+case 91:
+#line 814 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_MOD);
+ }
+break;
+case 92:
+#line 818 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_REM);
+ }
+break;
+case 93:
+#line 826 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 94:
+#line 830 "./ch-exp.y"
+{
+ write_exp_elt_opcode (UNOP_NEG);
+ }
+break;
+case 95:
+#line 834 "./ch-exp.y"
+{
+ write_exp_elt_opcode (UNOP_LOGICAL_NOT);
+ }
+break;
+case 96:
+#line 840 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_CONCAT);
+ }
+break;
+case 97:
+#line 848 "./ch-exp.y"
+{
+ write_exp_elt_opcode (UNOP_ADDR);
+ }
+break;
+case 98:
+#line 852 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 99:
+#line 856 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 100:
+#line 866 "./ch-exp.y"
+{
+ write_exp_elt_opcode (BINOP_ASSIGN);
+ }
+break;
+case 101:
+#line 875 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 102:
+#line 879 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 103:
+#line 883 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 104:
+#line 887 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 105:
+#line 891 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 106:
+#line 895 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 107:
+#line 899 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 108:
+#line 903 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 109:
+#line 907 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 110:
+#line 911 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 111:
+#line 915 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 112:
+#line 919 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 113:
+#line 925 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 114:
+#line 929 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 115:
+#line 933 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 116:
+#line 937 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 118:
+#line 946 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 119:
+#line 950 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 120:
+#line 956 "./ch-exp.y"
+{
+ yyval.voidval = 0; /* FIXME */
+ }
+break;
+case 121:
+#line 964 "./ch-exp.y"
+{
+ yyval.voidval = 0;
+ }
+break;
+case 122:
+#line 972 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 123:
+#line 973 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 124:
+#line 974 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 125:
+#line 975 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 126:
+#line 976 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 127:
+#line 977 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 128:
+#line 978 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 129:
+#line 979 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 130:
+#line 980 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 131:
+#line 981 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 132:
+#line 982 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 133:
+#line 983 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 134:
+#line 984 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 135:
+#line 985 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 136:
+#line 986 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 137:
+#line 987 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 138:
+#line 988 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 139:
+#line 989 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 140:
+#line 990 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+case 141:
+#line 991 "./ch-exp.y"
+{ yyval.voidval = 0; }
+break;
+#line 2799 "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/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..2f74061
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-lang.c
@@ -0,0 +1,341 @@
+/* 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;
+ 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)
+ 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)
+ {
+ chill_printchar ('\0', 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);
+ }
+}
+
+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, TYPE_FLAG_SIGNED, "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, TYPE_FLAG_SIGNED, "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, TYPE_FLAG_SIGNED, "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 */
+ &BUILTIN_TYPE_LONGEST, /* longest signed integral type */
+ &BUILTIN_TYPE_UNSIGNED_LONGEST,/* longest unsigned integral type */
+ &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..13579d9
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-lang.h
@@ -0,0 +1,31 @@
+/* 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. */
+
+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 *, FILE *, int, int));
+
+extern int
+chill_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, int, int,
+ int, enum val_prettyprint));
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..c3cdcd2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-typeprint.c
@@ -0,0 +1,225 @@
+/* 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 <string.h>
+#include <errno.h>
+
+static void
+chill_type_print_base PARAMS ((struct type *, FILE *, int, int));
+
+void
+chill_print_type (type, varstring, stream, show, level)
+ struct type *type;
+ char *varstring;
+ 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;
+ FILE *stream;
+ int show;
+ int level;
+{
+ char *name;
+ 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;
+ }
+
+ 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_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_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 ("CHAR (", 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:
+ fprintf_filtered (stream, "STRUCT ");
+ if ((name = type_name_no_tag (type)) != NULL)
+ {
+ fputs_filtered (name, stream);
+ fputs_filtered (" ", stream);
+ wrap_here (" ");
+ }
+ if (show < 0)
+ {
+ fprintf_filtered (stream, "(...)");
+ }
+ else
+ {
+ check_stub_type (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");
+ }
+ }
+ else
+ {
+ len = TYPE_NFIELDS (type);
+ for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+ {
+ QUIT;
+ print_spaces_filtered (level + 4, stream);
+ chill_print_type (TYPE_FIELD_TYPE (type, i),
+ 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_VOID:
+ case TYPE_CODE_UNDEF:
+ case TYPE_CODE_ERROR:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_ENUM:
+ 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..261b22e
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ch-valprint.c
@@ -0,0 +1,332 @@
+/* Support for printing Chill 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"
+#include "expression.h"
+#include "value.h"
+#include "language.h"
+#include "demangle.h"
+
+static void
+chill_print_value_fields PARAMS ((struct type *, char *, FILE *, int, int,
+ enum val_prettyprint, struct type **));
+
+
+/* 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;
+ 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, "[");
+ val_print_array_elements (type, valaddr, address, stream, format,
+ deref_ref, recurse, pretty, 0);
+ 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
+ {
+ 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);
+
+ 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')
+ {
+ fprintf_filtered (stream, "H'%lx", (unsigned long) addr);
+ }
+
+ /* 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;
+ }
+ if (addressprint && format != 's')
+ {
+ /* This used to say `addr', which is unset at this point.
+ Is `address' what is meant? */
+ fprintf_filtered (stream, "H'%lx ", (unsigned long) address);
+ }
+ 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_STRUCT:
+ chill_print_value_fields (type, valaddr, stream, format, recurse, pretty,
+ 0);
+ break;
+
+ case TYPE_CODE_REF:
+ if (addressprint)
+ {
+ fprintf_filtered (stream, "LOC(H'%lx)",
+ unpack_long (builtin_type_int, valaddr));
+ if (deref_ref)
+ fputs_filtered (": ", stream);
+ }
+ /* De-reference the reference. */
+ if (deref_ref)
+ {
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_UNDEF)
+ {
+ value 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_MEMBER:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_ERROR:
+ case TYPE_CODE_RANGE:
+ default:
+ /* Let's derfer printing to the C printer, rather than
+ print an error message. FIXME! */
+ c_val_print (type, valaddr, address, stream, format,
+ deref_ref, recurse, pretty);
+ }
+ fflush (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;
+ 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 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, "]");
+}
+
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..8c7cee2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coff/ecoff.h
@@ -0,0 +1,262 @@
+#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 _LIT4 ".lit4"
+#define _LIT8 ".lit8"
+#define _LIB ".lib"
+#define _INIT ".init"
+#define _FINI ".fini"
+
+/* 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_LIT8 0x8000000
+#define STYP_LIT4 0x10000000
+#define STYP_ECOFF_INIT 0x80000000
+#define STYP_OTHER_LOAD (STYP_ECOFF_INIT | STYP_ECOFF_FINI)
+
+/* 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"
+
+/* The ECOFF a.out header carries information about register masks and
+ the gp value. The assembler needs to be able to write out this
+ information, and objcopy needs to be able to copy it from one file
+ to another. To handle this in BFD, we use a dummy section to hold
+ the information. We call this section .reginfo, since MIPS ELF has
+ a .reginfo section which serves a similar purpose. When BFD
+ recognizes an ECOFF object, it copies the information into a
+ private data structure. When the .reginfo section is read, the
+ information is retrieved from the private data structure. When the
+ .reginfo section is written, the information in the private data
+ structure is updated. The contents of the .reginfo section, as
+ seen by programs outside BFD, is a ecoff_reginfo structure. The
+ contents of the structure are as seen on the host, so no swapping
+ issues arise.
+
+ The assembler used to update the private BFD data structures
+ directly. With this approach, it instead just creates a .reginfo
+ section and updates that. The real advantage of this approach is
+ that objcopy works automatically. */
+#define REGINFO ".reginfo"
+struct ecoff_reginfo
+{
+ 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. */
+};
+
+/* 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
+
+/********************** 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 0x80
+#define TIR_BITS1_FBITFIELD_LITTLE 0x01
+
+#define TIR_BITS1_CONTINUED_BIG 0x40
+#define TIR_BITS1_CONTINUED_LITTLE 0x02
+
+#define TIR_BITS1_BT_BIG 0x3F
+#define TIR_BITS1_BT_SH_BIG 0
+#define TIR_BITS1_BT_LITTLE 0xFC
+#define TIR_BITS1_BT_SH_LITTLE 2
+
+#define TIR_BITS_TQ4_BIG 0xF0
+#define TIR_BITS_TQ4_SH_BIG 4
+#define TIR_BITS_TQ5_BIG 0x0F
+#define TIR_BITS_TQ5_SH_BIG 0
+#define TIR_BITS_TQ4_LITTLE 0x0F
+#define TIR_BITS_TQ4_SH_LITTLE 0
+#define TIR_BITS_TQ5_LITTLE 0xF0
+#define TIR_BITS_TQ5_SH_LITTLE 4
+
+#define TIR_BITS_TQ0_BIG 0xF0
+#define TIR_BITS_TQ0_SH_BIG 4
+#define TIR_BITS_TQ1_BIG 0x0F
+#define TIR_BITS_TQ1_SH_BIG 0
+#define TIR_BITS_TQ0_LITTLE 0x0F
+#define TIR_BITS_TQ0_SH_LITTLE 0
+#define TIR_BITS_TQ1_LITTLE 0xF0
+#define TIR_BITS_TQ1_SH_LITTLE 4
+
+#define TIR_BITS_TQ2_BIG 0xF0
+#define TIR_BITS_TQ2_SH_BIG 4
+#define TIR_BITS_TQ3_BIG 0x0F
+#define TIR_BITS_TQ3_SH_BIG 0
+#define TIR_BITS_TQ2_LITTLE 0x0F
+#define TIR_BITS_TQ2_SH_LITTLE 0
+#define TIR_BITS_TQ3_LITTLE 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 0xF0
+#define RNDX_BITS1_RFD_SH_BIG 4
+
+#define RNDX_BITS0_RFD_SH_LEFT_LITTLE 0
+#define RNDX_BITS1_RFD_LITTLE 0x0F
+#define RNDX_BITS1_RFD_SH_LEFT_LITTLE 8
+
+#define RNDX_BITS1_INDEX_BIG 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 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)
+
+/* Prototypes for the swapping functions. These require that sym.h be
+ included before this file. */
+
+extern void ecoff_swap_tir_in PARAMS ((int bigend, struct tir_ext *, TIR *));
+extern void ecoff_swap_tir_out PARAMS ((int bigend, TIR *, struct tir_ext *));
+extern void ecoff_swap_rndx_in PARAMS ((int bigend, struct rndx_ext *,
+ RNDXR *));
+extern void ecoff_swap_rndx_out PARAMS ((int bigend, RNDXR *,
+ struct rndx_ext *));
+
+#endif /* ! defined (ECOFF_H) */
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..e8cf984
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coff/internal.h
@@ -0,0 +1,538 @@
+/* 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;
+ long o_sri;
+ long vid[2];
+};
+
+/********************** 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
+ {
+ long x_scnlen; /* csect length */
+ 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 RS/6000 and ECOFF */
+};
+
+#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 */
+
+
+/* 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
+
+
+
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..990eeac
--- /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 {
+ unsigned long 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 */
+ long 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 {
+ 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..e4ed620
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coff/symconst.h
@@ -0,0 +1,175 @@
+/* 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 */
+ /* Psuedo-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..eb0905b
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coffread.c
@@ -0,0 +1,2071 @@
+/* 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
+ 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 "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "gdb-stabs.h"
+#include "complaints.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 */
+
+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;
+
+/* Core address of the end of the first object file. */
+static CORE_ADDR first_object_file_end;
+
+/* The addresses of the symbol table stream and number of symbols
+ of the object file we are reading (as copied into core). */
+
+static 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
+
+struct pending_block *pending_blocks;
+
+/* 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 *
+getfilename PARAMS ((union internal_auxent *));
+
+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));
+
+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)
+ char *name;
+ CORE_ADDR address;
+ enum minimal_symbol_type type;
+{
+ /* 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);
+}
+
+/* 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, *strsection;
+ 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 ((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. */
+
+ sort_all_symtab_syms ();
+
+ /* 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 ((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;
+{
+ 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 num_object_files = 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, first_object_file_end);
+ /* 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);
+
+ 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 = 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! */
+ if (++num_object_files == 1) {
+ /* last address of startup file */
+ first_object_file_end = cs->c_value +
+ main_aux.x_scn.x_scnlen;
+ }
+ /* 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 external symbols in minsyms if we don't have debug
+ info for them. FIXME, this is probably the wrong thing
+ to do. Why don't we record them even if we do have
+ debug symbol info? What really belongs in the minsyms
+ anyway? Fred!?? */
+ if (!SDB_TYPE (cs->c_type)) {
+ /* FIXME: This is BOGUS Will Robinson!
+ Coff should provide the SEC_CODE flag for executable sections,
+ then if we could look up sections by section number we
+ could see if the flags indicate SEC_CODE. If so, then
+ record this symbol as a function in the minimal symbol table.
+ But why are absolute syms recorded as functions, anyway? */
+ if (cs->c_secnum <= text_bfd_scnum+1) {/* text or abs */
+ record_minimal_symbol (cs->c_name, cs->c_value,
+ mst_text);
+ break;
+ } else {
+ record_minimal_symbol (cs->c_name, cs->c_value,
+ mst_data);
+ break;
+ }
+ }
+ 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,
+ (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 (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. */
+
+static char *
+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;
+ struct type *temptype;
+
+ 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. */
+ 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. */
+ 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)
+ 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;
+ }
+
+#if 0
+ /* This screws up perfectly good C programs with enums. FIXME. */
+ /* Is this Modula-2's BOOLEAN type? Flag it as such if so. */
+ if(TYPE_NFIELDS(type) == 2 &&
+ ((STREQ(TYPE_FIELD_NAME(type,0),"TRUE") &&
+ STREQ(TYPE_FIELD_NAME(type,1),"FALSE")) ||
+ (STREQ(TYPE_FIELD_NAME(type,1),"TRUE") &&
+ STREQ(TYPE_FIELD_NAME(type,0),"FALSE"))))
+ TYPE_CODE(type) = TYPE_CODE_BOOL;
+#endif
+ return type;
+}
+
+struct section_offsets *
+coff_symfile_offsets (objfile, addr)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+{
+ struct section_offsets *section_offsets;
+ int i;
+
+ 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 =
+{
+ "coff", /* sym_name: name or name prefix of BFD target type */
+ 4, /* sym_namelen: number of significant sym_name chars */
+ 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..abc2d84
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/command.c
@@ -0,0 +1,1310 @@
+/* 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 *, 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 ((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;
+}
+
+/* ARGSUSED */
+void
+not_just_help_class_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+}
+
+/* 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;
+{
+ /* For set/show, we have to call do_setshow_command
+ differently than an ordinary function (take commandlist as
+ well as arg), so the function field isn't helpful. However,
+ function == NULL means that it's a help class, so set the function
+ to not_just_help_class_command. */
+ struct cmd_list_element *c
+ = add_cmd (name, class, not_just_help_class_command, doc, list);
+
+ c->type = set_cmd;
+ c->var_type = var_type;
+ c->var = var;
+ 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 (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;
+ 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;
+ 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)
+ 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;
+ 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);
+ char *ptr = (*line) + strlen (*line) - 1;
+
+ /* Clear off trailing whitespace. */
+ while (ptr >= *line && (*ptr == ' ' || *ptr == '\t'))
+ ptr--;
+ *(ptr + 1) = '\0';
+
+ 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. */
+ if (*p == 0)
+ break;
+ ch = parse_escape (&p);
+ if (ch == 0)
+ break; /* C loses */
+ else if (ch > 0)
+ *q++ = ch;
+ }
+ else
+ *q++ = ch;
+ }
+ if (*(p - 1) != '\\')
+ *q++ = ' ';
+ *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 (stdout, c->doc + 5);
+
+ fputs_filtered (" is ", stdout);
+ wrap_here (" ");
+ switch (c->var_type)
+ {
+ case var_string:
+ {
+ unsigned char *p;
+ fputs_filtered ("\"", stdout);
+ for (p = *(unsigned char **) c->var; *p != '\0'; p++)
+ gdb_printchar (*p, stdout, '"');
+ fputs_filtered ("\"", stdout);
+ }
+ break;
+ case var_string_noescape:
+ case var_filename:
+ fputs_filtered ("\"", stdout);
+ fputs_filtered (*(char **) c->var, stdout);
+ fputs_filtered ("\"", stdout);
+ break;
+ case var_boolean:
+ fputs_filtered (*(int *) c->var ? "on" : "off", stdout);
+ break;
+ case var_uinteger:
+ if (*(unsigned int *) c->var == UINT_MAX) {
+ fputs_filtered ("unlimited", stdout);
+ break;
+ }
+ /* else fall through */
+ case var_zinteger:
+ fprintf_filtered (stdout, "%u", *(unsigned int *) c->var);
+ break;
+ case var_integer:
+ if (*(int *) c->var == INT_MAX)
+ {
+ fputs_filtered ("unlimited", stdout);
+ }
+ else
+ fprintf_filtered (stdout, "%d", *(int *) c->var);
+ break;
+
+ default:
+ error ("gdb internal error: bad var_type in do_setshow_command");
+ }
+ fputs_filtered (".\n", 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, stdout);
+ fputs_filtered (list->name, stdout);
+ fputs_filtered (": ", 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 (stderr, "Exec of shell failed\n");
+ exit (0);
+ }
+
+ 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;
+ 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, stdout);
+ }
+ else
+ {
+ for (c = cmdlist; c; c = c->next)
+ {
+ if (c->class == class_user)
+ show_user_1 (c, 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..ee587c3
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/command.h
@@ -0,0 +1,241 @@
+/* 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.
+ Zero for command class names and for help topics that
+ are not really commands. */
+ union {
+ void (*cfunc) PARAMS ((char *args, int from_tty));
+ 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 *, FILE *));
+
+extern void
+help_list PARAMS ((struct cmd_list_element *, char *, enum command_class,
+ FILE *));
+
+extern void
+help_cmd_list PARAMS ((struct cmd_list_element *, enum command_class, char *,
+ int, 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/complaints.c b/gnu/usr.bin/gdb/gdb/complaints.c
new file mode 100644
index 0000000..079ca5a
--- /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. */
+ fflush (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..f7ff5a5
--- /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..36c9ab5
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/core.c
@@ -0,0 +1,291 @@
+/* Core dump and executable file functions above 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. */
+
+#include "defs.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"
+
+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 ("Cannot access memory at address %s.",
+ local_hex_string((unsigned long) memaddr));
+ }
+ else
+ {
+ error ("Error accessing memory address %s: %s.",
+ local_hex_string ((unsigned long) memaddr),
+ safe_strerror (status));
+ }
+}
+
+/* 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);
+}
+
+/* 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..d94fd98
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/coredep.c
@@ -0,0 +1,118 @@
+/* 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"
+
+/* 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
+
+#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. */
+
+ /* 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
+ 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 < NUM_REGS; regno++)
+ {
+ addr = 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 >= 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..1cebc48
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/corelow.c
@@ -0,0 +1,328 @@
+/* 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. */
+
+#include "defs.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"
+
+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. */
+
+static int
+solib_add_stub (from_tty)
+ char *from_tty;
+{
+ SOLIB_ADD (NULL, (int)from_tty, &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_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_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, (char *)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 (stderr, "Couldn't fetch registers from core file: %s\n",
+ bfd_errmsg (bfd_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 (stderr, "Couldn't fetch register set 2 from core file: %s\n",
+ bfd_errmsg (bfd_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;
+{
+}
+
+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..47b38f8
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/cp-valprint.c
@@ -0,0 +1,484 @@
+/* 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"
+
+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 *, 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 *, FILE *, int, int));
+
+extern void
+c_type_print_varspec_prefix PARAMS ((struct type *, FILE *, int, int));
+
+extern void
+cp_type_print_method_args PARAMS ((struct type **, char *, char *, int,
+ FILE *));
+
+extern struct obstack dont_print_obstack;
+
+/* END-FIXME */
+
+
+/* BEGIN-FIXME: Hooks into c-valprint.c */
+
+extern int
+c_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, int, int, int,
+ enum val_prettyprint));
+/* END-FIXME */
+
+
+void
+cp_print_class_method (valaddr, type, stream)
+ char *valaddr;
+ struct type *type;
+ 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 (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);
+ }
+}
+
+/* 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);
+ /* 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. */
+ static const char vtbl_ptr_name[] =
+ { '_','_','v','t','b','l','_','p','t','r','_','t','y','p','e', 0 };
+
+ 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);
+ else
+ return 0;
+
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_STRUCT)
+ /* Virtual functions tables are full of pointers to virtual functions. */
+ return cp_is_vtbl_ptr_type (TYPE_TARGET_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;
+ 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
+ {
+ fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
+ language_cplus,
+ DMGL_PARAMS | DMGL_ANSI);
+ fputs_filtered (" = ", stream);
+ }
+ if (TYPE_FIELD_PACKED (type, i))
+ {
+ value 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));
+
+ c_val_print (TYPE_FIELD_TYPE (type, i), VALUE_CONTENTS (v), 0,
+ stream, format, 0, recurse + 1, pretty);
+ }
+ else
+ {
+ c_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, "}");
+}
+
+/* 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;
+ 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++)
+ {
+ char *baddr;
+ int err;
+ char *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 0x%lx>", (unsigned long) baddr);
+ 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;
+ 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..7f4ef26
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dbxread.c
@@ -0,0 +1,2234 @@
+/* Read dbx symbol tables and convert to internal format, for GDB.
+ Copyright 1986, 1987, 1988, 1989, 1990, 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. */
+
+/* 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 "libbfd.h" /* FIXME Secret internal BFD stuff (bfd_read) */
+#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
+
+/* 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
+
+/* 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
+
+/* 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;
+
+/* 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 type character `%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_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;
+
+ switch (type)
+ {
+ case N_TEXT | N_EXT: ms_type = mst_text; break;
+ case N_DATA | N_EXT: ms_type = mst_data; break;
+ case N_BSS | N_EXT: ms_type = mst_bss; break;
+ case N_ABS | N_EXT: ms_type = mst_abs; break;
+#ifdef N_SETV
+ case N_SETV | N_EXT: ms_type = mst_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;
+ break;
+#endif
+ case N_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;
+
+ {
+ char *tempstring = name;
+ if (tempstring[0] == bfd_get_symbol_leading_char (objfile->obfd))
+ ++tempstring;
+ if (STREQN (tempstring, "__gnu_compiled", 14))
+ return;
+ }
+
+ case N_NBTEXT:
+ case N_FN:
+ case N_FN_SEQ:
+ ms_type = mst_file_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;
+ }
+ break;
+
+ case N_BSS:
+ ms_type = mst_file_bss;
+ break;
+
+ default: ms_type = mst_unknown; break;
+ }
+
+ prim_record_minimal_symbol
+ (obsavestring (name, strlen (name), &objfile -> symbol_obstack),
+ address,
+ ms_type);
+}
+
+/* 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;
+
+ 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)));
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile. */
+
+ install_minimal_symbols (objfile);
+
+ if (!have_partial_symbols ()) {
+ wrap_here ("");
+ printf_filtered ("(no debugging symbols found)...");
+ wrap_here ("");
+ }
+
+ 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;
+}
+
+/* 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;
+
+ /* End of the text segment of the executable file. */
+ CORE_ADDR end_of_text_addr;
+
+ /* 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;
+
+#ifdef END_OF_TEXT_DEFAULT
+ end_of_text_addr = END_OF_TEXT_DEFAULT;
+#else
+ end_of_text_addr = text_addr + section_offsets->offsets[SECT_OFF_TEXT]
+ + text_size; /* Relocate */
+#endif
+
+ 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 = "foo"; \
+ } 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, end_of_text_addr,
+ 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;
+/* struct partial_symbol *capping_global, *capping_static;*/
+{
+ int i;
+ struct partial_symtab *p1;
+ struct objfile *objfile = pst -> objfile;
+
+ if (capping_symbol_offset != -1)
+ LDSYMLEN(pst) = capping_symbol_offset - LDSYMOFF(pst);
+ pst->texthigh = capping_text;
+
+ /* 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)
+ 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) {
+ 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. */
+
+
+ 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. */
+ 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 (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 (" ", stdout);
+ wrap_here ("");
+ fputs_filtered ("and ", stdout);
+ wrap_here ("");
+ printf_filtered ("%s...", pst->dependencies[i]->filename);
+ wrap_here (""); /* Flush output */
+ fflush (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 (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);
+ fflush (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)
+ {
+ if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 1;
+ else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL))
+ 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, N_LBRAC, N_RBRAC, and N_SLINE entries are relative
+ to the function start address. */
+ int block_address_function_relative;
+
+ /* 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;
+
+ /* This is true for Solaris (and all other stabs-in-elf systems, 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);
+
+ 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 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. Defined the block for them.
+
+ If 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. However, if
+ it is so, we need to indicate that we just moved outside
+ of the function. */
+ if (local_symbols
+ && (context_stack_depth
+ > !VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation)))
+ {
+ /* FIXME Muzzle a compiler bug that makes end < start. */
+ 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
+ {
+ 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 ();
+ }
+ 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;
+ p = strchr (name, ':');
+ if (p != 0 && p[1] == 'S')
+ {
+ /* The linker relocated it. There used to be a kludge here
+ to add the text offset, but that will break if we ever
+ start using the text offset (currently it is always zero). */
+ 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((unsigned long) 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 PA symbol file.
+ This PA file has already been processed to get its minimal symbols.
+
+ 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).
+
+ */
+
+void
+pastab_build_psymtabs (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+{
+ free_header_files ();
+ init_header_files ();
+
+ /* In a PA file, we've already installed the minimal symbols that came
+ from the PA (non-stab) symbol table, so always act like an
+ incremental load here. */
+
+ dbx_symfile_read (objfile, section_offsets, mainline);
+}
+
+/* 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;
+
+ 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 willingness to decode symbols for SunOS and a.out and
+ NetBSD and b.out files handled by BFD... */
+static struct sym_fns sunos_sym_fns =
+{
+ "sunOs", /* sym_name: name or name prefix of BFD target type */
+ 6, /* sym_namelen: number of significant sym_name chars */
+ 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 */
+};
+
+static struct sym_fns aout_sym_fns =
+{
+ "a.out", /* sym_name: name or name prefix of BFD target type */
+ 5, /* sym_namelen: number of significant sym_name chars */
+ 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 */
+};
+
+static struct sym_fns bout_sym_fns =
+{
+ "b.out", /* sym_name: name or name prefix of BFD target type */
+ 5, /* sym_namelen: number of significant sym_name chars */
+ 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(&sunos_sym_fns);
+ add_symtab_fns(&aout_sym_fns);
+ add_symtab_fns(&bout_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..aaa01d0
--- /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..f65d56a
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/defs.h
@@ -0,0 +1,901 @@
+/* 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"
+
+/* An address in the program being debugged. Host byte order. */
+#ifndef CORE_ADDR_TYPE
+typedef unsigned int CORE_ADDR;
+#else
+typedef CORE_ADDR_TYPE CORE_ADDR;
+#endif
+
+#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 */
+};
+
+/* 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 ();
+
+extern void
+begin_line PARAMS ((void));
+
+extern void
+wrap_here PARAMS ((char *));
+
+extern void
+reinitialize_more_filter PARAMS ((void));
+
+extern int
+print_insn PARAMS ((CORE_ADDR, FILE *));
+
+extern void
+fputs_filtered PARAMS ((const char *, FILE *));
+
+extern void
+puts_filtered 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
+print_spaces PARAMS ((int, FILE *));
+
+extern void
+print_spaces_filtered PARAMS ((int, FILE *));
+
+extern char *
+n_spaces PARAMS ((int));
+
+extern void
+gdb_printchar PARAMS ((int, FILE *, int));
+
+extern void
+fprintf_symbol_filtered PARAMS ((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));
+
+extern void
+print_prompt PARAMS ((void));
+
+extern int
+batch_mode 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, FILE *, int, char *));
+
+extern void
+print_address PARAMS ((CORE_ADDR, 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"
+
+/* 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
+
+/* 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
+
+/* Default to support for "long long" if the host compiler being used is gcc.
+ Config files must define CC_HAS_LONG_LONG to use other host compilers
+ that are capable of supporting "long long", and to cause gdb to use that
+ support. Not defining CC_HAS_LONG_LONG will suppress use of "long long"
+ regardless of what compiler is used.
+
+ FIXME: For now, automatic selection of "long long" as the default when
+ gcc is used is disabled, pending further testing. Concerns include the
+ impact on gdb performance and the universality of bugfree long long
+ support on platforms that do have gcc. Compiling with FORCE_LONG_LONG
+ will select "long long" use for testing purposes. -fnf */
+
+#ifndef CC_HAS_LONG_LONG
+# if defined (__GNUC__) && defined (FORCE_LONG_LONG) /* See FIXME above */
+# 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
+
+/* 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. */
+
+#ifndef longest_to_int
+# ifdef CC_HAS_LONG_LONG
+# define longest_to_int(x) (((x) > INT_MAX || (x) < INT_MIN) \
+ ? (error ("Value out of range."),0) : (int) (x))
+# else
+ /* Assume sizeof (int) == sizeof (long). */
+# define longest_to_int(x) ((int) (x))
+# endif
+#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
+
+/* 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[];
+
+extern NORETURN void /* Does not return to the caller. */
+error ();
+
+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 ((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 (*comp)(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
+# ifdef sparc
+# include <alloca.h> /* NOTE: Doesn't declare alloca() */
+# endif
+# ifdef __STDC__
+ extern void *alloca (size_t);
+# else /* __STDC__ */
+ extern char *alloca ();
+# endif
+# endif
+#endif
+
+/* 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"
+
+/* 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. */
+
+/* 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.
+ extract_* are the right way. */
+#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. */
+
+/* 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));
+
+/* 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));
+
+/* In some modules, we don't have a definition of REGISTER_TYPE yet, so we
+ must avoid prototyping this function for now. FIXME. Should be:
+extern CORE_ADDR
+push_word PARAMS ((CORE_ADDR, REGISTER_TYPE));
+ */
+extern CORE_ADDR
+push_word ();
+
+/* 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..a134bb7
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/demangle.c
@@ -0,0 +1,190 @@
+/* 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}
+};
+
+/* show current demangling style. */
+
+static void
+show_demangling_command (ignore, from_tty)
+ char *ignore;
+ int from_tty;
+{
+ /* done automatically by show command. */
+}
+
+
+/* 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)
+ char *ignore;
+ int from_tty;
+{
+ 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 ("Unknown demangling style `%s'.\n",
+ current_demangling_style_string);
+ }
+ printf ("The currently understood settings are:\n\n");
+ for (dem = demanglers; dem -> demangling_style_name != NULL; dem++)
+ {
+ printf ("%-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 =
+ strdup (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 =
+ strdup (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 = strdup (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.cfunc = set_demangling_command;
+ show -> function.cfunc = show_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..4f191a2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/demangle.h
@@ -0,0 +1,77 @@
+/* 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));
+
+/* 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..e7f106c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dis-asm.h
@@ -0,0 +1,176 @@
+/* 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*));
+
+
+
+
+
+
+/* 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..d07da6f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dis-buf.c
@@ -0,0 +1,69 @@
+/* Disassemble from a buffer, for GNU.
+ 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. */
+
+#include "dis-asm.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/dwarfread.c b/gnu/usr.bin/gdb/gdb/dwarfread.c
new file mode 100644
index 0000000..5d19bf8
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/dwarfread.c
@@ -0,0 +1,3866 @@
+/* DWARF debugging format support for GDB.
+ Copyright (C) 1991, 1992 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 <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 BFD stuff (bfd_read) */
+#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>
+#include <sys/types.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;
+ }
+ switch (di.die_tag)
+ {
+ case TAG_compile_unit:
+ read_file_scope (&di, thisdie, nextdie, objfile);
+ 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 (" ", stdout);
+ wrap_here ("");
+ fputs_filtered ("and ", stdout);
+ wrap_here ("");
+ printf_filtered ("%s...",
+ pst -> dependencies[i] -> filename);
+ wrap_here ("");
+ fflush (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 ("");
+ fflush (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);
+ fflush (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");
+ fflush (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:
+ 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..cd708f1
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/elf/common.h
@@ -0,0 +1,216 @@
+/* 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 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 */
+#define EM_HPPA 9 /* HP PA-RISC */
+
+
+/* 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_LORESERV 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) ((unsigned char)(i))
+#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t))
+
+#define ELF64_R_SYM(i) ((i)>>32)
+#define ELF64_R_TYPE(i) ((Elf64_Word)(i))
+#define ELF64_R_INFO(s,t) (((Elf64_Xword)(s)<<32)+(Elf64_Xword)(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..bc9723ae
--- /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..f2ab63e
--- /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..ae4bdad
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/elf/internal.h
@@ -0,0 +1,195 @@
+/* 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 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. */
+
+/* Types used by various structures, functions, etc. */
+
+typedef unsigned long Elf32_Addr; /* Unsigned program address */
+typedef unsigned long Elf32_Off; /* Unsigned file offset */
+typedef long Elf32_Sword; /* Signed large integer */
+typedef unsigned long Elf32_Word; /* Unsigned large integer */
+typedef unsigned short Elf32_Half; /* Unsigned medium integer */
+typedef unsigned char Elf32_Char; /* Unsigned tiny integer */
+
+#ifdef HOST_64_BIT
+typedef unsigned HOST_64_BIT Elf64_Addr;
+typedef unsigned HOST_64_BIT Elf64_Off;
+typedef HOST_64_BIT Elf64_Sxword;
+typedef unsigned HOST_64_BIT Elf64_Xword;
+#endif
+typedef long Elf64_Sword;
+typedef unsigned long Elf64_Word;
+typedef unsigned short Elf64_Half;
+
+/* 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. */
+ void *rawdata; /* null if unused... */
+ void *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 {
+ Elf32_Sword d_tag; /* entry tag value */
+ union {
+ Elf32_Word d_val;
+ Elf32_Addr d_ptr;
+ } d_un;
+} Elf32_Internal_Dyn;
+
+#ifdef HOST_64_BIT
+typedef struct {
+ Elf64_Xword d_tag; /* entry tag value */
+ union {
+ Elf64_Xword d_val;
+ Elf64_Addr d_ptr;
+ } d_un;
+} Elf64_Internal_Dyn;
+#endif
diff --git a/gnu/usr.bin/gdb/gdb/elfread.c b/gnu/usr.bin/gdb/gdb/elfread.c
new file mode 100644
index 0000000..230afec
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/elfread.c
@@ -0,0 +1,729 @@
+/* Read ELF (Executable and Linking Format) object files 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. */
+
+#include "defs.h"
+#include "bfd.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" /* For bfd_elf_find_section */
+#include "libelf.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "gdb-stabs.h"
+#include "complaints.h"
+#include <string.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 */
+};
+
+/* 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 *));
+
+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;
+ }
+}
+
+#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;
+ 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);
+}
+
+/*
+
+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)
+ bfd *abfd;
+ CORE_ADDR addr;
+ struct objfile *objfile;
+{
+ unsigned int storage_needed;
+ asymbol *sym;
+ asymbol **symbol_table;
+ unsigned int number_of_symbols;
+ unsigned int 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;
+
+ storage_needed = get_symtab_upper_bound (abfd);
+ 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);
+ 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 (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_abs_section)
+ {
+ 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')
+ /* 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.
+
+ 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);
+
+ /* 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)
+ {
+ /* STABS sections */
+
+ /* FIXME: Sun didn't really know how to implement this well.
+ They made .stab sections that don't point to the .stabstr
+ section with the sh_link field. BFD doesn't make string table
+ sections visible to the caller. So we have to search the
+ ELF section table, not the BFD section table, for the string
+ table. */
+ struct elf32_internal_shdr *elf_sect;
+
+ elf_sect = bfd_elf_find_section (abfd, ".stabstr");
+ if (elf_sect)
+ elfstab_build_psymtabs (objfile,
+ section_offsets,
+ mainline,
+ ei.stabsect->filepos, /* .stab offset */
+ bfd_get_section_size_before_reloc (ei.stabsect),/* .stab size */
+ (file_ptr) elf_sect->sh_offset, /* .stabstr offset */
+ elf_sect->sh_size); /* .stabstr size */
+ }
+
+ if (!have_partial_symbols ())
+ {
+ wrap_here ("");
+ printf_filtered ("(no debugging symbols found)...");
+ wrap_here ("");
+ }
+
+ /* 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;
+
+ 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 and DWARF
+ debugging formats.
+
+ Unlike other object file formats, where the debugging information format
+ is implied by the object file format, the ELF object file format and the
+ DWARF debugging information format are two distinct, and potentially
+ separate entities. I.E. it is perfectly possible to have ELF objects
+ with debugging formats other than DWARF. And it is conceivable that the
+ DWARF debugging format might be used with another object file format,
+ like COFF, by simply using COFF's custom section feature.
+
+ GDB, and to a lesser extent BFD, should support the notion of separate
+ object file formats and debugging information formats. For now, we just
+ use "elf" in the same sense as "a.out" or "coff", to imply both the ELF
+ object file format and the DWARF debugging format. */
+
+static struct sym_fns elf_sym_fns =
+{
+ "elf", /* sym_name: name or name prefix of BFD target type */
+ 3, /* sym_namelen: number of significant sym_name chars */
+ 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..4089212
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/environ.c
@@ -0,0 +1,198 @@
+/* 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 "defs.h" /* For strsave(). */
+
+
+/* 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;
+
+ 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;
+
+ /* Certain variables get exported back to the parent (e.g. our)
+ environment, too. FIXME: this is a hideous hack and should not be
+ allowed to live. What if we want to change the environment we pass to
+ the program without affecting GDB's behavior? */
+ if (STREQ(var, "PATH")) /* Object file location */
+ {
+ putenv (strsave (s));
+ }
+
+ /* This is a compatibility hack, since GDB 4.10 and older didn't have
+ `set gnutarget'. Eventually it should go away, so that (for example)
+ you can debug objdump's handling of GNUTARGET without affecting GDB's
+ behavior. */
+ if (STREQ (var, "GNUTARGET"))
+ {
+ set_gnutarget (value);
+ }
+ 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..f641a65
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/eval.c
@@ -0,0 +1,1213 @@
+/* Evaluate expressions 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. */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "value.h"
+#include "expression.h"
+#include "target.h"
+#include "frame.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
+evaluate_subexp_for_sizeof PARAMS ((struct expression *, int *));
+
+static value
+evaluate_subexp_with_coercion PARAMS ((struct expression *, int *,
+ enum noside));
+
+static value
+evaluate_subexp_for_address PARAMS ((struct expression *, int *,
+ enum noside));
+
+static value
+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
+parse_and_eval (exp)
+ char *exp;
+{
+ struct expression *expr = parse_expression (exp);
+ register value 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
+parse_to_comma_and_eval (expp)
+ char **expp;
+{
+ struct expression *expr = parse_exp_1 (expp, (struct block *) 0, 1);
+ register value 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. */
+
+static value evaluate_subexp ();
+static value evaluate_subexp_for_address ();
+static value evaluate_subexp_for_sizeof ();
+static value evaluate_subexp_with_coercion ();
+
+value
+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
+evaluate_type (exp)
+ struct expression *exp;
+{
+ int pc = 0;
+ return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_AVOID_SIDE_EFFECTS);
+}
+
+static value
+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 arg1 = NULL, arg2 = NULL, arg3;
+ struct type *type;
+ int nargs;
+ value *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 *) alloca (sizeof (value) * 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 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 *) alloca (sizeof (value) * (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 temp = arg2;
+
+ argvec[1] = arg2;
+ argvec[0] =
+ value_struct_elt (&temp, argvec+1, &exp->elts[pc2 + 2].string,
+ &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 temp = arg1;
+ return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 2].string,
+ (int *) 0, "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 temp = arg1;
+ return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 2].string,
+ (int *) 0, "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 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
+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 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
+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 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
+evaluate_subexp_for_sizeof (exp, pos)
+ register struct expression *exp;
+ register int *pos;
+{
+ enum exp_opcode op;
+ register int pc;
+ value 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..f66a33c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/exec.c
@@ -0,0 +1,489 @@
+/* Work with executable files, 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. */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+#include "gdbcmd.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_error));
+ if (!bfd_check_format (exec_bfd, bfd_object))
+ error ("\"%s\": not in executable format: %s.",
+ scratch_pathname, bfd_errmsg (bfd_error));
+
+ if (build_section_table (exec_bfd, &exec_ops.to_sections,
+ &exec_ops.to_sections_end))
+ error ("Can't find the file sections in `%s': %s",
+ exec_bfd->filename, bfd_errmsg (bfd_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->sec_ptr)
+ & (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 ("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);
+ /* FIXME, we need to handle BSS segment here...it alloc's but doesn't load */
+ if (!(aflag & SEC_LOAD))
+ return;
+ if (0 == bfd_section_size (abfd, asect))
+ return;
+ (*table_pp)->bfd = abfd;
+ (*table_pp)->sec_ptr = 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->sec_ptr, myaddr, memaddr - p->addr, len);
+ return (res != false)? 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->sec_ptr, myaddr, memaddr - p->addr, len);
+ return (res != false)? 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));
+ printf_filtered ("\tEntry point: %s\n",
+ local_hex_string ((unsigned long) bfd_get_start_address (exec_bfd)));
+ for (p = t->to_sections; p < t->to_sections_end; p++) {
+ 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->sec_ptr->filepos, "08l"));
+ printf_filtered (" is %s", bfd_section_name (p->bfd, p->sec_ptr));
+ 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->sec_ptr), seclen)
+ && bfd_section_name (exec_bfd, p->sec_ptr)[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..607b3df
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/expprint.c
@@ -0,0 +1,623 @@
+/* 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 *, FILE *, enum precedence));
+
+static void
+print_simple_m2_func PARAMS ((char *, struct expression *, int *, FILE *));
+
+void
+print_expression (exp, stream)
+ struct expression *exp;
+ 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;
+ 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 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 (stream, " [");
+ for (tem = 0; tem < nargs; tem++)
+ {
+ if (tem != 0)
+ fprintf (stream, ", ");
+ print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+ }
+ fprintf (stream, "]");
+ return;
+
+ case BINOP_VAL:
+ (*pos)+=2;
+ fprintf(stream,"VAL(");
+ type_print(exp->elts[pc+1].type,"",stream,0);
+ fprintf(stream,",");
+ print_subexp(exp,pos,stream,PREC_PREFIX);
+ fprintf(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;
+ FILE *stream;
+{
+ fprintf(stream,"%s(",s);
+ print_subexp(exp,pos,stream,PREC_PREFIX);
+ fprintf(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;
+ FILE *stream;
+ char *note;
+{
+ int elt;
+ char *opcode_name;
+ char *eltscan;
+ int eltsize;
+
+ fprintf_filtered (stream, "Dump of expression @ 0x%lx, %s:\n",
+ (unsigned long) exp, 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..521c25c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/expression.h
@@ -0,0 +1,313 @@
+/* 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,
+
+ /* 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 *, 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 *, 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..bf50e1f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/findvar.c
@@ -0,0 +1,971 @@
+/* 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);
+}
+
+#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
+value_of_register (regnum)
+ int regnum;
+{
+ CORE_ADDR addr;
+ int optim;
+ register value val;
+ char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+ enum lval_type lval;
+
+ get_saved_register (raw_buffer, &optim, &addr,
+ selected_frame, regnum, &lval);
+
+ REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer);
+ val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
+ memcpy (VALUE_CONTENTS_RAW (val), virtual_buffer,
+ REGISTER_VIRTUAL_SIZE (regnum));
+ VALUE_LVAL (val) = lval;
+ VALUE_ADDRESS (val) = addr;
+ VALUE_REGNO (val) = regnum;
+ VALUE_OPTIMIZED_OUT (val) = optim;
+ return 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];
+
+/* Indicate that registers may have changed, so invalidate the cache. */
+void
+registers_changed ()
+{
+ int i;
+ for (i = 0; i < NUM_REGS; i++)
+ register_valid[i] = 0;
+}
+
+/* Indicate that all registers have been fetched, so mark them all valid. */
+void
+registers_fetched ()
+{
+ int i;
+ for (i = 0; i < NUM_REGS; 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;
+ for (i = 0; i < NUM_REGS; 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 (!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;
+{
+ /* 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 (!register_valid[regno])
+ target_fetch_registers (regno);
+
+ return extract_address (&registers[REGISTER_BYTE (regno)],
+ REGISTER_RAW_SIZE(regno));
+}
+
+/* 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;
+
+ 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])
+ {
+ if (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);
+}
+
+/* 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;
+{
+ 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
+}
+
+/* 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;
+ }
+}
+
+/* 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
+read_var_value (var, frame)
+ register struct symbol *var;
+ FRAME frame;
+{
+ register value 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);
+
+ v = value_from_register (type, SYMBOL_VALUE (var), frame);
+
+ if (SYMBOL_CLASS (var) == LOC_REGPARM_ADDR)
+ {
+ addr = *(CORE_ADDR *)VALUE_CONTENTS (v);
+ VALUE_LVAL (v) = lval_memory;
+ }
+ else
+ return v;
+ }
+ 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
+value_from_register (type, regnum, frame)
+ struct type *type;
+ int regnum;
+ FRAME frame;
+{
+ char raw_buffer [MAX_REGISTER_RAW_SIZE];
+ char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+ CORE_ADDR addr;
+ int optim;
+ value 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 the raw contents to virtual contents.
+ (Just copy them if the formats are the same.) */
+
+ REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer);
+
+ if (REGISTER_CONVERTIBLE (regnum))
+ {
+ /* When the raw and virtual formats differ, the virtual format
+ corresponds to a specific data type. If we want that type,
+ copy the data into the value.
+ Otherwise, do a type-conversion. */
+
+ if (type != REGISTER_VIRTUAL_TYPE (regnum))
+ {
+ /* eg a variable of type `float' in a 68881 register
+ with raw type `extended' and virtual type `double'.
+ Fetch it as a `double' and then convert to `float'. */
+ /* FIXME: This value will be not_lval, which means we can't assign
+ to it. Probably the right fix is to do the cast on a temporary
+ value, and just copy the VALUE_CONTENTS over. */
+ v = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
+ memcpy (VALUE_CONTENTS_RAW (v), virtual_buffer,
+ REGISTER_VIRTUAL_SIZE (regnum));
+ v = value_cast (type, v);
+ }
+ else
+ memcpy (VALUE_CONTENTS_RAW (v), virtual_buffer, len);
+ }
+ else
+ {
+ /* 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), virtual_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
+locate_var_value (var, frame)
+ register struct symbol *var;
+ FRAME frame;
+{
+ CORE_ADDR addr = 0;
+ struct type *type = SYMBOL_TYPE (var);
+ value 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/fopen-same.h b/gnu/usr.bin/gdb/gdb/fopen-same.h
new file mode 100644
index 0000000..0f37529
--- /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..3c01b60
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/fork-child.c
@@ -0,0 +1,310 @@
+/* Fork a Unix child process, and set up to debug it, 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 "terminal.h"
+
+#include <signal.h>
+
+#ifdef SET_STACK_LIMIT_HUGE
+#include <sys/time.h>
+#include <sys/resource.h>
+
+extern int original_stack_limit;
+#endif /* SET_STACK_LIMIT_HUGE */
+
+extern char **environ;
+
+/* 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(). */
+
+#ifndef SHELL_FILE
+#define SHELL_FILE "/bin/sh"
+#endif
+
+void
+fork_inferior (exec_file, allargs, env, traceme_fun, init_trace_fun)
+ char *exec_file;
+ char *allargs;
+ char **env;
+ void (*traceme_fun) PARAMS ((void));
+ void (*init_trace_fun) PARAMS ((int));
+{
+ int pid;
+ char *shell_command;
+ char *shell_file;
+ static char default_shell_file[] = SHELL_FILE;
+ int len;
+ int pending_execs;
+ int terminal_initted;
+ /* 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, this should probably search the local environment (as
+ modified by the setenv command), not the env gdb inherited. */
+ 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. */
+
+ fflush (stdout);
+ fflush (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");
+
+#ifdef SET_STACK_LIMIT_HUGE
+ /* Reset the stack limit back to what it was. */
+ {
+ struct rlimit rlim;
+
+ getrlimit (RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = original_stack_limit;
+ setrlimit (RLIMIT_STACK, &rlim);
+ }
+#endif /* SET_STACK_LIMIT_HUGE */
+
+ /* 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 (stderr, "Cannot exec %s: %s.\n", shell_file,
+ safe_strerror (errno));
+ fflush (stderr);
+ _exit (0177);
+ }
+
+ /* Restore our environment in case a vforked child clob'd it. */
+ environ = save_our_env;
+
+ init_thread_list();
+
+ /* Now that we have a child process, make it our target, and
+ initialize anything target-vector-specific that needs initializing. */
+ (*init_trace_fun)(pid);
+
+ /* 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. */
+
+ inferior_pid = pid; /* Needed for wait_for_inferior stuff below */
+
+ clear_proceed_status ();
+
+ /* We will get a trace trap after one instruction.
+ Continue it automatically. Eventually (after shell does an exec)
+ it will get another trace trap. Then insert breakpoints and continue. */
+
+#ifdef START_INFERIOR_TRAPS_EXPECTED
+ pending_execs = START_INFERIOR_TRAPS_EXPECTED;
+#else
+ pending_execs = 2;
+#endif
+
+ init_wait_for_inferior ();
+
+ terminal_initted = 0;
+
+ while (1)
+ {
+ stop_soon_quietly = 1; /* Make wait_for_inferior be quiet */
+ wait_for_inferior ();
+ if (stop_signal != SIGTRAP)
+ {
+ /* 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, 0); /* Just make it go on */
+ }
+ }
+ stop_soon_quietly = 0;
+
+ /* 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
+}
diff --git a/gnu/usr.bin/gdb/gdb/frame.h b/gnu/usr.bin/gdb/gdb/frame.h
new file mode 100644
index 0000000..1fe6fb6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/frame.h
@@ -0,0 +1,238 @@
+/* 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, 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 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..deb68eb
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/freebsd-nat.c
@@ -0,0 +1,323 @@
+/* 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. */
+
+#include "defs.h"
+#include <machine/reg.h>
+
+/* this table must line up with REGISTER_NAMES in tm-i386.h */
+/* symbols like 'tEAX' come from <machine/reg.h> */
+static int tregmap[] =
+{
+ tEAX, tECX, tEDX, tEBX,
+ tESP, tEBP, tESI, tEDI,
+ tEIP, tEFLAGS, tCS, tSS
+};
+#ifdef sEAX
+static int sregmap[] =
+{
+ sEAX, sECX, sEDX, sEBX,
+ sESP, sEBP, sESI, sEDI,
+ sEIP, sEFLAGS, sCS, sSS
+};
+#endif
+/* 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;
+{
+ /* The following condition is a kludge to get at the proper register map
+ depending upon the state of pcb_flag.
+ The proper condition would be
+ if (u.u_pcb.pcb_flag & FM_TRAP)
+ but that would require a ptrace call here and wouldn't work
+ for corefiles. */
+
+#ifdef sEAX
+ if (blockend < 0x1fcc)
+ return (blockend + 4 * tregmap[regnum]);
+ else
+ return (blockend + 4 * sregmap[regnum]);
+#else
+ return (blockend + 4 * tregmap[regnum]);
+#endif
+}
+
+#ifdef FLOAT_INFO
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <a.out.h>
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/uio.h>
+#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */
+#include <sys/user.h>
+#undef curpcb
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/ptrace.h>
+
+#define fpstate save87
+#define U_FPSTATE(u) u.u_pcb.pcb_savefpu
+
+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 */
+}
+
+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");
+}
+
+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];
+};
+
+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);
+}
+
+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
+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 ("last exception: ");
+ 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 `p->regs.
+ */
+ st_regno = (fpreg + 8 - top) & 0x7;
+
+ 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);
+ }
+}
+
+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
+ {
+ printf("float info: can't do a core file (yet)\n");
+
+ return;
+#if 0
+ 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
+ }
+
+ print_387_status (0, (struct env387 *)buf);
+}
+
+#endif
diff --git a/gnu/usr.bin/gdb/gdb/freebsd-solib.c b/gnu/usr.bin/gdb/gdb/freebsd-solib.c
new file mode 100644
index 0000000..5b6e4c0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/freebsd-solib.c
@@ -0,0 +1,1469 @@
+/* Handle SunOS and SVR4 shared libraries for GDB, the GNU Debugger.
+ Copyright 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. */
+/* modified for FreeBSD, since the names in link.h are totally different!
+ 6.1.94 */
+
+#include "defs.h"
+
+#include <sys/types.h>
+#include <signal.h>
+#include <string.h>
+#ifndef SVR4_SHARED_LIBS
+ /* SunOS shared libs need the nlist structure. */
+#include <a.out.h>
+#endif
+#include <link.h>
+#include <sys/param.h>
+#include <fcntl.h>
+
+#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 "regex.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
+
+/* local data declarations */
+
+#ifndef SVR4_SHARED_LIBS
+
+#define DEBUG_BASE "_DYNAMIC"
+#ifdef OLD_FreeBSD_LD
+#define LM_ADDR(so) ((so) -> lm.lm_addr)
+#define LM_NEXT(so) ((so) -> lm.lm_next)
+#define LM_NAME(so) ((so) -> lm.lm_name)
+static struct link_dynamic dynamic_copy;
+static struct link_dynamic_2 ld_2_copy;
+static struct ld_debug debug_copy;
+#else
+#define LM_ADDR(so) ((so) -> lm.som_addr)
+#define LM_NEXT(so) ((so) -> lm.som_next)
+#define LM_NAME(so) ((so) -> lm.som_path)
+static struct _dynamic dynamic_copy;
+static struct section_dispatch_table ld_2_copy;
+static struct so_debug debug_copy;
+#endif
+static CORE_ADDR debug_addr;
+static CORE_ADDR flag_addr;
+
+#else /* SVR4_SHARED_LIBS */
+
+#define DEBUG_BASE "_r_debug"
+#define LM_ADDR(so) ((so) -> lm.l_addr)
+#define LM_NEXT(so) ((so) -> lm.l_next)
+#define LM_NAME(so) ((so) -> lm.l_name)
+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 */
+#ifdef OLD_FreeBSD_LD
+ struct link_map lm; /* copy of link map from inferior */
+ struct link_map *lmaddr; /* addr in inferior lm was read from */
+#else
+ struct so_map lm; /* copy of link map from inferior */
+ struct so_map *lmaddr; /* addr in inferior lm was read from */
+#endif
+ 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 *));
+
+#ifdef OLD_FreeBSD_LD
+static struct link_map *
+#else
+static struct so_map *
+#endif
+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 int
+look_for_base PARAMS ((int, CORE_ADDR));
+
+static CORE_ADDR
+bfd_lookup_symbol PARAMS ((bfd *, char *));
+
+#else
+
+static void
+solib_add_common_symbols PARAMS ((struct rt_symbol *, 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_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_error));
+ }
+ if (build_section_table (abfd, &so -> sections, &so -> sections_end))
+ {
+ error ("Can't find the file sections in `%s': %s",
+ bfd_get_filename (exec_bfd), bfd_errmsg (bfd_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 -> sec_ptr -> 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 rt_symbol *rtc_symp;
+ struct objfile *objfile;
+{
+ struct rt_symbol inferior_rtc_symb;
+ struct nzlist inferior_rtc_nzlist;
+ 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.rt_sp,
+ (char *) &inferior_rtc_nzlist,
+ sizeof(inferior_rtc_nzlist));
+ if (inferior_rtc_nzlist.nz_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_nzlist.nz_value - inferior_rtc_nzlist.nz_strx;
+
+ origname = name = xmalloc (len);
+ read_memory ((CORE_ADDR) inferior_rtc_nzlist.nz_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_nzlist.nz_value,
+ mst_bss);
+ }
+ free (origname);
+ }
+ rtc_symp = inferior_rtc_symb.rt_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
+
+/*
+
+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).
+
+ FIXME: See if there is a less "expensive" way of doing this.
+ Also see if there is already another bfd or gdb function
+ that specifically does this, and if so, use it.
+*/
+
+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 = 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 symbol DEBUG_BASE 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;
+
+ /* 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) || fdmatch (fileno ((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. */
+
+ if ((address = bfd_lookup_symbol (interp_bfd, DEBUG_BASE)) == 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
+
+/*
+
+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 symbol defined by the macro DEBUG_BASE.
+ 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 much more complicated because 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. We have to go
+ to a lot more work to discover the address of DEBUG_BASE. 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.
+
+ Note that we can assume nothing about the process state at the time
+ we need to find this address. We may be stopped on the first instruc-
+ tion 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 CORE_ADDR
+locate_base ()
+{
+
+#ifndef SVR4_SHARED_LIBS
+
+ struct minimal_symbol *msymbol;
+ CORE_ADDR address = 0;
+
+ /* For SunOS, we want to limit the search for DEBUG_BASE to the executable
+ being debugged, since there is a duplicate named symbol in the shared
+ library. We don't want the shared library versions. */
+
+ msymbol = lookup_minimal_symbol (DEBUG_BASE, symfile_objfile);
+ if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0))
+ {
+ address = SYMBOL_VALUE_ADDRESS (msymbol);
+ }
+ return (address);
+
+#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, ask the /proc support interface to iterate
+ over the list of mapped address segments, calling look_for_base() for
+ each segment. When we are done, we will have either found the base
+ address or not. */
+
+ if (debug_base == 0)
+ {
+ proc_iterate_over_mappings (look_for_base);
+ }
+ 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.
+*/
+
+#ifdef OLD_FreeBSD_LD
+static struct link_map *
+#else
+static struct so_map *
+#endif
+first_link_map_member ()
+{
+#ifdef OLD_FreeBSD_LD
+ struct link_map *lm = NULL;
+#else
+ struct so_map *lm = NULL;
+#endif
+
+#ifndef SVR4_SHARED_LIBS
+
+ read_memory (debug_base, (char *) &dynamic_copy, sizeof (dynamic_copy));
+#ifdef OLD_FreeBSD_LD
+ 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
+ if (dynamic_copy.d_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.d_un.d_sdt, (char *) &ld_2_copy,
+ sizeof (struct section_dispatch_table));
+ lm = ld_2_copy.sdt_loaded;
+ }
+#endif
+#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;
+#ifdef OLD_FreeBSD_LD
+ struct link_map *lm = NULL;
+#else
+ struct so_map *lm = NULL;
+#endif
+ 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),
+#ifdef OLD_FreeBSD_LD
+ sizeof (struct link_map));
+#else
+ sizeof (struct so_map));
+#endif
+ 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),
+#ifdef OLD_FreeBSD_LD
+ sizeof (struct link_map));
+#else
+ sizeof (struct so_map));
+#endif
+ /* For the SVR4 version, there is one entry that has no name
+ (for the inferior executable) since it is not a shared object. */
+ if (LM_NAME (new) != 0)
+ {
+ if (!target_read_string((CORE_ADDR) LM_NAME (new), new -> so_name,
+ MAX_PATH_SIZE - 1))
+ error ("find_solib: Can't read pathname for load map\n");
+ new -> so_name[MAX_PATH_SIZE - 1] = 0;
+ 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,
+ (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);
+ }
+
+ /* Getting new symbols may change our opinion about what is
+ frameless. */
+ reinit_frame_cache ();
+
+ 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 ("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;
+ }
+ }
+ }
+
+ /* Now add the shared library sections to the section table of the
+ specified target, if any. */
+ 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;
+ }
+ }
+ }
+ }
+
+ /* 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 ("No exec file.\n");
+ return;
+ }
+ while ((so = find_solib (so)) != NULL)
+ {
+ if (so -> so_name[0])
+ {
+ if (!header_done)
+ {
+ printf("%-12s%-12s%-12s%s\n", "From", "To", "Syms Read",
+ "Shared Object Library");
+ header_done++;
+ }
+ printf ("%-12s",
+ local_hex_string_custom ((unsigned long) LM_ADDR (so),
+ "08l"));
+ printf ("%-12s",
+ local_hex_string_custom ((unsigned long) so -> lmend,
+ "08l"));
+ printf ("%-12s", so -> symbols_loaded ? "Yes" : "No");
+ printf ("%s\n", so -> so_name);
+ }
+ }
+ if (so_list_head == NULL)
+ {
+ printf ("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));
+
+#ifdef OLD_FreeBSD_LD
+ 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
+ breakpoint_addr = (CORE_ADDR) debug_copy.dd_bpt_addr;
+ write_memory (breakpoint_addr, (char *) &debug_copy.dd_bpt_shadow,
+ sizeof (debug_copy.dd_bpt_shadow));
+#endif
+
+#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 */
+
+#ifdef OLD_FreeBSD_LD
+ debug_addr = (CORE_ADDR) dynamic_copy.ldd;
+#else
+ debug_addr = (CORE_ADDR) dynamic_copy.d_debug;
+#endif
+
+ /* Calc address of `in_debugger' member of debugger interface structure */
+
+#ifdef OLD_FreeBSD_LD
+ flag_addr = debug_addr + (CORE_ADDR) ((char *) &debug_copy.ldd_in_debugger -
+ (char *) &debug_copy);
+#else
+ flag_addr = debug_addr + (CORE_ADDR) ((char *) &debug_copy.dd_in_debugger -
+ (char *) &debug_copy);
+#endif
+
+ /* 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 = 0;
+ do
+ {
+ target_resume (-1, 0, stop_signal);
+ wait_for_inferior ();
+ }
+ while (stop_signal != SIGTRAP);
+ 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). */
+
+#ifdef OLD_FreeBSD_LD
+ debug_addr = (CORE_ADDR) dynamic_copy.ldd;
+#else
+ debug_addr = (CORE_ADDR) dynamic_copy.d_debug;
+#endif
+ }
+
+ /* 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. */
+
+#ifdef OLD_FreeBSD_LD
+ if (debug_copy.ldd_cp)
+ {
+ solib_add_common_symbols (debug_copy.ldd_cp, so -> objfile);
+ }
+#else
+ if (debug_copy.dd_cc)
+ {
+ solib_add_common_symbols (debug_copy.dd_cc, so -> objfile);
+ }
+#endif
+
+#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/gdb-stabs.h b/gnu/usr.bin/gdb/gdb/gdb-stabs.h
new file mode 100644
index 0000000..c1e0253
--- /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..ccb216e
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdb.1
@@ -0,0 +1,371 @@
+.\" Copyright (c) 1991 Free Software Foundation
+.\" See section COPYING for conditions for redistribution
+.\" $Id: gdb.1,v 1.1.1.1 1993/10/30 21:59:13 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 "[\|" \-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 \-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..ec0f1b5
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdbcore.h
@@ -0,0 +1,129 @@
+/* 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));
+
+/* If this is prototyped, need to deal with void* vs. char*. */
+
+extern void
+write_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
+
+/* 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;
+
+ /* 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/gdbtypes.c b/gnu/usr.bin/gdb/gdb/gdbtypes.c
new file mode 100644
index 0000000..f346469
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdbtypes.c
@@ -0,0 +1,1440 @@
+/* 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);
+}
+
+
+/* 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;
+
+ if (TYPE_CODE (range_type) != TYPE_CODE_RANGE)
+ {
+ /* FIXME: We only handle range types at the moment. Complain and
+ create a dummy range type to use. */
+ warning ("internal error: array index type must be a range type");
+ range_type = lookup_fundamental_type (TYPE_OBJFILE (range_type),
+ FT_INTEGER);
+ range_type = create_range_type ((struct type *) NULL, range_type, 0, 0);
+ }
+ 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_FIELD_BITPOS (range_type, 0);
+ high_bound = TYPE_FIELD_BITPOS (range_type, 1);
+ 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);
+}
+
+/* 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;
+
+ if (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 ();
+ fflush (stdout);
+ fprintf (stderr, "Type ");
+ type_print (type, "", 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 ();
+ fflush (stdout);
+ fprintf (stderr, "Type ");
+ type_print (type, "", stderr, -1);
+ fprintf (stderr, " has no component named ");
+ fputs_filtered (name, 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. If not, set a flag so we
+ don't waste too much time in future. (FIXME, this doesn't seem
+ to be happening...)
+
+ 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));
+ }
+ }
+}
+
+/* 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;
+ argtypes[0] = lookup_pointer_type (type);
+ argcount = 1;
+
+ if (*p != ')') /* () means no args, skip while */
+ {
+ depth = 0;
+ while (*p)
+ {
+ if (depth <= 0 && (*p == ',' || *p == ')'))
+ {
+ 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);
+}
+
+#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 0x%lx\n",
+ (unsigned long) TYPE_FN_FIELDLISTS (type));
+ 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' (0x%lx) length %d\n",
+ method_idx,
+ TYPE_FN_FIELDLIST_NAME (type, method_idx),
+ (unsigned long) TYPE_FN_FIELDLIST_NAME (type, method_idx),
+ 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' (0x%lx)\n",
+ overload_idx,
+ TYPE_FN_FIELD_PHYSNAME (f, overload_idx),
+ (unsigned long) TYPE_FN_FIELD_PHYSNAME (f, overload_idx));
+ printfi_filtered (spaces + 8, "type 0x%lx\n",
+ (unsigned long) TYPE_FN_FIELD_TYPE (f, overload_idx));
+ recursive_dump_type (TYPE_FN_FIELD_TYPE (f, overload_idx),
+ spaces + 8 + 2);
+ printfi_filtered (spaces + 8, "args 0x%lx\n",
+ (unsigned long) TYPE_FN_FIELD_ARGS (f, overload_idx));
+ print_arg_types (TYPE_FN_FIELD_ARGS (f, overload_idx), spaces);
+ printfi_filtered (spaces + 8, "fcontext 0x%lx\n",
+ (unsigned long) TYPE_FN_FIELD_FCONTEXT (f, overload_idx));
+ 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 *0x%lx)",
+ TYPE_N_BASECLASSES (type),
+ (unsigned long) TYPE_FIELD_VIRTUAL_BITS (type));
+ 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 *0x%lx)",
+ TYPE_NFIELDS (type),
+ (unsigned long) TYPE_FIELD_PRIVATE_BITS (type));
+ 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 *0x%lx)",
+ TYPE_NFIELDS (type),
+ (unsigned long) TYPE_FIELD_PROTECTED_BITS (type));
+ 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 0x%lx\n", (unsigned long)type);
+ printfi_filtered (spaces, "name '%s' (0x%lx)\n",
+ TYPE_NAME (type) ? TYPE_NAME (type) : "<NULL>",
+ (unsigned long)TYPE_NAME (type));
+ if (TYPE_TAG_NAME (type) != NULL)
+ printfi_filtered (spaces, "tagname '%s' (0x%lx)\n",
+ TYPE_TAG_NAME (type),
+ (unsigned long)TYPE_TAG_NAME (type));
+ 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 0x%lx\n",
+ (unsigned long) TYPE_OBJFILE (type));
+ printfi_filtered (spaces, "target_type 0x%lx\n",
+ (unsigned long) TYPE_TARGET_TYPE (type));
+ if (TYPE_TARGET_TYPE (type) != NULL)
+ {
+ recursive_dump_type (TYPE_TARGET_TYPE (type), spaces + 2);
+ }
+ printfi_filtered (spaces, "pointer_type 0x%lx\n",
+ (unsigned long) TYPE_POINTER_TYPE (type));
+ printfi_filtered (spaces, "reference_type 0x%lx\n",
+ (unsigned long) TYPE_REFERENCE_TYPE (type));
+ printfi_filtered (spaces, "function_type 0x%lx\n",
+ (unsigned long) TYPE_FUNCTION_TYPE (type));
+ 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_SIGNED)
+ {
+ puts_filtered (" TYPE_FLAG_SIGNED");
+ }
+ if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+ {
+ puts_filtered (" TYPE_FLAG_STUB");
+ }
+ puts_filtered ("\n");
+ printfi_filtered (spaces, "nfields %d 0x%lx\n", TYPE_NFIELDS (type),
+ (unsigned long) TYPE_FIELDS (type));
+ for (idx = 0; idx < TYPE_NFIELDS (type); idx++)
+ {
+ printfi_filtered (spaces + 2,
+ "[%d] bitpos %d bitsize %d type 0x%lx name '%s' (0x%lx)\n",
+ idx, TYPE_FIELD_BITPOS (type, idx),
+ TYPE_FIELD_BITSIZE (type, idx),
+ (unsigned long) TYPE_FIELD_TYPE (type, idx),
+ TYPE_FIELD_NAME (type, idx) != NULL
+ ? TYPE_FIELD_NAME (type, idx)
+ : "<NULL>",
+ (unsigned long) TYPE_FIELD_NAME (type, idx));
+ if (TYPE_FIELD_TYPE (type, idx) != NULL)
+ {
+ recursive_dump_type (TYPE_FIELD_TYPE (type, idx), spaces + 4);
+ }
+ }
+ printfi_filtered (spaces, "vptr_basetype 0x%lx\n",
+ (unsigned long) TYPE_VPTR_BASETYPE (type));
+ 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 0x%lx\n",
+ (unsigned long) TYPE_ARG_TYPES (type));
+ print_arg_types (TYPE_ARG_TYPES (type), spaces);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ printfi_filtered (spaces, "cplus_stuff 0x%lx\n",
+ (unsigned long) TYPE_CPLUS_SPECIFIC (type));
+ 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 0x%lx",
+ (unsigned long) TYPE_CPLUS_SPECIFIC (type));
+ 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,
+ TYPE_FLAG_SIGNED,
+ "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..89cad6c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/gdbtypes.h
@@ -0,0 +1,704 @@
+/* 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
+
+/* When gdb creates fundamental types, it uses one of the following
+ type identifiers. The identifiers are used to index a vector of
+ pointers to any types that are created. */
+
+#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 (values zero length; the length field is ignored). */
+ TYPE_CODE_VOID,
+
+ TYPE_CODE_SET, /* Pascal sets */
+ TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */
+ TYPE_CODE_STRING, /* String types, distinct from array of char */
+ TYPE_CODE_BITSTRING, /* String of bits, distinct from bool array */
+
+ /* 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 */
+
+ /* Modula-2 */
+ TYPE_CODE_CHAR, /* *real* character type */
+ TYPE_CODE_BOOL /* BOOLEAN type */
+};
+
+/* For now allow source to use TYPE_CODE_CLASS for C++ classes, as an
+ alias for TYPE_CODE_STRUCT. Eventually these should probably be
+ officially distinct types within gdb. */
+
+#define TYPE_CODE_CLASS TYPE_CODE_STRUCT
+
+/* Some bits for the type's flags word. */
+
+/* Explicitly unsigned integer type */
+
+#define TYPE_FLAG_UNSIGNED (1 << 0)
+
+/* Explicitly signed integer type */
+
+#define TYPE_FLAG_SIGNED (1 << 1)
+
+/* 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)
+
+
+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, 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. */
+
+ 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
+
+/* 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_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_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_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;
+
+/* CC_HAS_LONG_LONG is defined if the host has "long long". */
+
+#ifdef CC_HAS_LONG_LONG
+
+#define BUILTIN_TYPE_LONGEST builtin_type_long_long
+#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long_long
+
+#else /* not CC_HAS_LONG_LONG. */
+
+#define BUILTIN_TYPE_LONGEST builtin_type_long
+#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long
+
+#endif /* not CC_HAS_LONG_LONG. */
+
+/* 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 *
+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, FILE *));
+
+#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..3e4bbb2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/i386-dis.c
@@ -0,0 +1,1952 @@
+/* Print i386 instructions for GDB, the GNU debugger.
+ Copyright (C) 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. */
+
+/*
+ * 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"
+
+#define MAXLEN 20
+
+#include <setjmp.h>
+
+struct 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 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 private *priv = (struct 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, Xb },
+ { "scasS", eAX, Xv },
+ /* 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 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_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..b6d7fe9
--- /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;
+ 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..3c64d72
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/i386-tdep.c
@@ -0,0 +1,595 @@
+/* Intel 386 target-dependent stuff.
+ Copyright (C) 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 "frame.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "target.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;
+ fsrp->regs[op - 0x50] = adr;
+ 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;
+
+ 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 ();
+ }
+
+ 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))
+ {
+ extern struct ext_format ext_format_i387;
+ double d;
+ /* 387 %st(0), gcc uses this */
+ ieee_extended_to_double (&ext_format_i387,
+ &regbuf[REGISTER_BYTE(FP0_REGNUM)],
+ &d);
+ switch (TYPE_LENGTH(type))
+ {
+ case 4: /* float */
+ {
+ float f = (float) d;
+ memcpy (valbuf, &f, 4);
+ break;
+ }
+ case 8: /* double */
+ memcpy (valbuf, &d, 8);
+ break;
+ default:
+ error("Unknown floating point size");
+ break;
+ }
+ }
+ else
+ {
+ memcpy (valbuf, regbuf, TYPE_LENGTH (type));
+ }
+}
+#endif /* I386_AIX_TARGET */
diff --git a/gnu/usr.bin/gdb/gdb/infcmd.c b/gnu/usr.bin/gdb/gdb/infcmd.c
new file mode 100644
index 0000000..5859ed2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/infcmd.c
@@ -0,0 +1,1423 @@
+/* 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"
+
+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). */
+
+int 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 ();
+ }
+
+ 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 ();
+
+ 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");
+ fflush (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, -1, 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);
+ fflush (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, -1, 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 %s.\n",
+ local_hex_string((unsigned long) addr));
+
+ clear_proceed_status ();
+ proceed (addr, 0, 0);
+}
+
+/* Continue program giving it specified signal. */
+
+static void
+signal_command (signum_exp, from_tty)
+ char *signum_exp;
+ int from_tty;
+{
+ register int signum;
+
+ 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. */
+ signum = strtosigno (signum_exp);
+
+ if (signum == 0)
+ /* Not found as a name, try it as an expression. */
+ signum = parse_and_eval_address (signum_exp);
+
+ if (from_tty)
+ {
+ char *signame = strsigno (signum);
+ printf_filtered ("Continuing with signal ");
+ if (signame == NULL || signum == 0)
+ printf_filtered ("%d.\n", signum);
+ else
+ /* Do we need to print the number as well as the name? */
+ printf_filtered ("%s (%d).\n", signame, signum);
+ }
+
+ clear_proceed_status ();
+ proceed (stop_pc, signum, 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 = entry_point_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, 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. I'm going to postpone this until after a hopeful rewrite
+ of wait_for_inferior and the proceed status code. -- randy */
+
+/* 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, -1, 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, -1, 0);
+
+ /* Did we stop at our breakpoint? */
+ if (bpstat_find_breakpoint(stop_bpstat, breakpoint) != NULL
+ && function != 0)
+ {
+ struct type *value_type;
+ register value 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, 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)
+ {
+#ifdef PRINT_RANDOM_SIGNAL
+ PRINT_RANDOM_SIGNAL (stop_signal);
+#else
+ char *signame = strsigno (stop_signal);
+ printf_filtered ("It stopped with signal ");
+ if (signame == NULL)
+ printf_filtered ("%d", stop_signal);
+ else
+ /* Do we need to print the number as well as the name? */
+ printf_filtered ("%s (%d)", signame, stop_signal);
+ printf_filtered (", %s.\n", safe_strsignal (stop_signal));
+#endif
+ }
+
+ 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);
+}
+
+/* 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 ();
+#else
+ return ADDR_BITS_REMOVE ((CORE_ADDR) read_register (PC_REGNUM));
+#endif
+}
+
+void
+write_pc (val)
+ CORE_ADDR val;
+{
+#ifdef TARGET_WRITE_PC
+ TARGET_WRITE_PC (val);
+#else
+ write_register (PC_REGNUM, (long) val);
+#ifdef NPC_REGNUM
+ write_register (NPC_REGNUM, (long) val + 4);
+#ifdef NNPC_REGNUM
+ write_register (NNPC_REGNUM, (long) val + 8);
+#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
+}
+
+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;
+
+ for (i = 0; i < NUM_REGS; 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], stdout);
+ print_spaces_filtered (15 - strlen (reg_names[i]), stdout);
+
+ /* Get the data in raw format, then convert also to virtual format. */
+ if (read_relative_register_raw_bytes (i, raw_buffer))
+ {
+ printf_filtered ("Invalid register contents\n");
+ continue;
+ }
+
+ REGISTER_CONVERT_TO_VIRTUAL (i, raw_buffer, virtual_buffer);
+
+ /* 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,
+ 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,
+ stdout, 'x', 1, 0, Val_pretty_default);
+ printf_filtered ("\t");
+ val_print (REGISTER_VIRTUAL_TYPE (i), raw_buffer, 0,
+ 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;
+ 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;
+ for (regnum = 0; regnum < NUM_REGS; 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 >= NUM_REGS) /* 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;
+
+ wait_for_inferior ();
+
+#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 */
+ 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, 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..0f5499a
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/inferior.h
@@ -0,0 +1,401 @@
+/* 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"
+
+/*
+ * 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 {
+ int 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;
+};
+
+extern void
+save_inferior_status PARAMS ((struct inferior_status *, int));
+
+extern void
+restore_inferior_status PARAMS ((struct inferior_status *));
+
+/* 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, int, 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 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, int));
+
+/* 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, int));
+
+#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)));
+
+/* 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 int 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
+extern CORE_ADDR
+entry_point_address PARAMS ((void));
+#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
+ ((pc) >= entry_point_address () \
+ && (pc) <= (entry_point_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..be0b43b
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/inflow.c
@@ -0,0 +1,662 @@
+/* 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 <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));
+
+/* Nonzero if we are debugging an attached outside process
+ rather than an inferior. */
+
+int attach_flag;
+
+
+/* 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;
+ }
+}
+
+/* Macro for printing errors from ioctl operations */
+
+#define OOPSY(what) \
+ if (result == -1) \
+ fprintf(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
+ inferior_process_group = inferior_pid;
+#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. */
+
+ /* 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 (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", stdout);
+ else
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+ }
+}
+
+/* The inferior process has died. Long live the inferior! */
+
+void
+generic_mourn_inferior ()
+{
+ 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. */
+ breakpoint_clear_ignore_counts ();
+}
+
+/* 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);
+}
+
+
+int job_control;
+
+/* 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..a152d67
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/infptrace.c
@@ -0,0 +1,436 @@
+/* Low level Unix child interface to ptrace, for GDB when running under Unix.
+ Copyright 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. */
+
+#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. */
+ kill (inferior_pid, SIGKILL);
+ ptrace (PT_KILL, inferior_pid, (PTRACE_ARG3_TYPE) 0, 0);
+ wait ((int *)0);
+ target_mourn_inferior ();
+}
+
+/* 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;
+ int signal;
+{
+ errno = 0;
+
+ if (pid == -1)
+ 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, signal);
+ else
+ ptrace (PT_CONTINUE, pid, (PTRACE_ARG3_TYPE) 1, signal);
+
+ if (errno)
+ perror_with_name ("ptrace");
+}
+
+#ifdef ATTACH_DETACH
+/* Start debugging the process whose number is PID. */
+int
+attach (pid)
+ int pid;
+{
+ errno = 0;
+ ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0);
+ if (errno)
+ perror_with_name ("ptrace");
+ 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;
+{
+ errno = 0;
+ ptrace (PT_DETACH, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal);
+ if (errno)
+ perror_with_name ("ptrace");
+ 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
+
+#if !defined (FETCH_INFERIOR_REGISTERS)
+
+/* 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)
+/* Get kernel_u_addr using BSD-style nlist(). */
+CORE_ADDR kernel_u_addr;
+
+void
+_initialize_kernel_u_addr ()
+{
+ 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 (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;
+{
+ register unsigned int 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;
+{
+ if (regno == -1)
+ for (regno = 0; regno < NUM_REGS; 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;
+{
+ register unsigned int regaddr;
+ char buf[80];
+ register int i;
+
+ 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
+ {
+ for (regno = 0; regno < NUM_REGS; 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). */
+
+/* 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;
+}
diff --git a/gnu/usr.bin/gdb/gdb/infrun.c b/gnu/usr.bin/gdb/gdb/infrun.c
new file mode 100644
index 0000000..9266c31
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/infrun.c
@@ -0,0 +1,1848 @@
+/* Target-struct-independent code to start (run) and stop an inferior process.
+ Copyright 1986, 1987, 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 <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 <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 ((int));
+
+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 ".init" 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;
+ int 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;
+ int 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;
+ }
+ else
+ write_pc (addr);
+
+ 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 >= 0)
+ stop_signal = siggnal;
+ /* If this signal should not be seen by program,
+ give it zero. Used for debugging signals. */
+ else if (stop_signal < NSIG && !signal_program[stop_signal])
+ stop_signal= 0;
+
+ /* 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;
+
+
+/* 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;
+
+ trap_expected_after_continue = 0;
+ breakpoints_inserted = 0;
+ breakpoint_init_inferior ();
+ stop_signal = 0; /* Don't confuse first call to proceed(). */
+}
+
+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;
+ WAITTYPE w;
+ int another_trap;
+ int random_signal;
+ CORE_ADDR stop_sp = 0;
+ CORE_ADDR stop_func_start;
+ 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;
+ int handling_longjmp = 0; /* FIXME */
+ struct breakpoint *step_resume_breakpoint = NULL;
+ int pid;
+
+ old_cleanups = make_cleanup (delete_breakpoint_current_contents,
+ &step_resume_breakpoint);
+ sal = find_pc_line(prev_pc, 0);
+ current_line = sal.line;
+
+ /* Are we stepping? */
+#define CURRENTLY_STEPPING() ((step_resume_breakpoint == NULL \
+ && !handling_longjmp \
+ && (step_range_end \
+ || trap_expected)) \
+ || bpstat_should_step ())
+
+ while (1)
+ {
+ /* Clean up saved state that will become invalid. */
+ flush_cached_frames ();
+ registers_changed ();
+
+ pid = target_wait (-1, &w);
+
+#ifdef SIGTRAP_STOP_AFTER_LOAD
+
+ /* Somebody called load(2), and it gave us a "trap signal after load".
+ Ignore it gracefully. */
+
+ SIGTRAP_STOP_AFTER_LOAD (w);
+#endif
+
+ /* See if the process still exists; clean up if it doesn't. */
+ if (WIFEXITED (w))
+ {
+ target_terminal_ours (); /* Must do this before mourn anyway */
+ if (WEXITSTATUS (w))
+ printf_filtered ("\nProgram exited with code 0%o.\n",
+ (unsigned int)WEXITSTATUS (w));
+ else
+ if (!batch_mode())
+ printf_filtered ("\nProgram exited normally.\n");
+ fflush (stdout);
+ target_mourn_inferior ();
+#ifdef NO_SINGLE_STEP
+ one_stepped = 0;
+#endif
+ stop_print_frame = 0;
+ break;
+ }
+ else if (!WIFSTOPPED (w))
+ {
+ char *signame;
+
+ stop_print_frame = 0;
+ stop_signal = WTERMSIG (w);
+ target_terminal_ours (); /* Must do this before mourn anyway */
+ target_kill (); /* kill mourns as well */
+#ifdef PRINT_RANDOM_SIGNAL
+ printf_filtered ("\nProgram terminated: ");
+ PRINT_RANDOM_SIGNAL (stop_signal);
+#else
+ printf_filtered ("\nProgram terminated with signal ");
+ signame = strsigno (stop_signal);
+ if (signame == NULL)
+ printf_filtered ("%d", stop_signal);
+ else
+ /* Do we need to print the number in addition to the name? */
+ printf_filtered ("%s (%d)", signame, stop_signal);
+ printf_filtered (", %s\n", safe_strsignal (stop_signal));
+#endif
+ printf_filtered ("The program no longer exists.\n");
+ fflush (stdout);
+#ifdef NO_SINGLE_STEP
+ one_stepped = 0;
+#endif
+ break;
+ }
+
+ stop_signal = WSTOPSIG (w);
+
+ if (pid != inferior_pid)
+ {
+ int save_pid = inferior_pid;
+
+ inferior_pid = pid; /* Setup for target memory/regs */
+ registers_changed ();
+ stop_pc = read_pc ();
+ inferior_pid = save_pid;
+ registers_changed ();
+ }
+ else
+ stop_pc = read_pc ();
+
+ if (stop_signal == SIGTRAP
+ && breakpoint_here_p (stop_pc - DECR_PC_AFTER_BREAK))
+ if (!breakpoint_thread_match (stop_pc - DECR_PC_AFTER_BREAK, pid))
+ {
+ /* Saw a breakpoint, but it was hit by the wrong thread. Just continue. */
+ if (breakpoints_inserted)
+ {
+ remove_breakpoints ();
+ target_resume (pid, 1, 0); /* Single step */
+ /* FIXME: What if a signal arrives instead of the single-step
+ happening? */
+ target_wait (pid, NULL);
+ insert_breakpoints ();
+ }
+ target_resume (-1, 0, 0);
+ continue;
+ }
+ else
+ if (pid != inferior_pid)
+ goto switch_thread;
+
+ if (pid != inferior_pid)
+ {
+ int printed = 0;
+
+ if (!in_thread_list (pid))
+ {
+ fprintf (stderr, "[New %s]\n", target_pid_to_str (pid));
+ add_thread (pid);
+
+ target_resume (-1, 0, 0);
+ continue;
+ }
+ else
+ {
+ if (stop_signal >= NSIG || signal_print[stop_signal])
+ {
+ char *signame;
+
+ printed = 1;
+ target_terminal_ours_for_output ();
+ printf_filtered ("\nProgram received signal ");
+ signame = strsigno (stop_signal);
+ if (signame == NULL)
+ printf_filtered ("%d", stop_signal);
+ else
+ printf_filtered ("%s (%d)", signame, stop_signal);
+ printf_filtered (", %s\n", safe_strsignal (stop_signal));
+
+ fflush (stdout);
+ }
+
+ if (stop_signal == SIGTRAP
+ || stop_signal >= NSIG
+ || signal_stop[stop_signal])
+ {
+switch_thread:
+ inferior_pid = pid;
+ printf_filtered ("[Switching to %s]\n", target_pid_to_str (pid));
+
+ flush_cached_frames ();
+ registers_changed ();
+ trap_expected = 0;
+ if (step_resume_breakpoint)
+ {
+ delete_breakpoint (step_resume_breakpoint);
+ step_resume_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;
+ }
+ else
+ {
+ if (printed)
+ target_terminal_inferior ();
+
+ /* Clear the signal if it should not be passed. */
+ if (signal_program[stop_signal] == 0)
+ stop_signal = 0;
+
+ target_resume (-1, 0, stop_signal);
+ continue;
+ }
+ }
+ }
+
+same_pid:
+
+#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));
+
+ 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,
+ NULL);
+ 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 == SIGTRAP
+ || (breakpoints_inserted &&
+ (stop_signal == SIGILL
+#ifdef SIGEMT
+ || stop_signal == SIGEMT
+#endif
+ ))
+ || stop_soon_quietly)
+ {
+ if (stop_signal == SIGTRAP && 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 step_resume_breakpoint
+ will be set and we should check whether we've hit the
+ step breakpoint. */
+ if (stop_signal == SIGTRAP && trap_expected
+ && step_resume_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 == SIGTRAP)
+ 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 = SIGTRAP;
+ }
+ }
+ 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 (stop_signal >= NSIG
+ || signal_print[stop_signal])
+ {
+ char *signame;
+ printed = 1;
+ target_terminal_ours_for_output ();
+#ifdef PRINT_RANDOM_SIGNAL
+ PRINT_RANDOM_SIGNAL (stop_signal);
+#else
+ printf_filtered ("\nProgram received signal ");
+ signame = strsigno (stop_signal);
+ if (signame == NULL)
+ printf_filtered ("%d", stop_signal);
+ else
+ /* Do we need to print the number as well as the name? */
+ printf_filtered ("%s (%d)", signame, stop_signal);
+ printf_filtered (", %s\n", safe_strsignal (stop_signal));
+#endif /* PRINT_RANDOM_SIGNAL */
+ fflush (stdout);
+ }
+ if (stop_signal >= NSIG
+ || 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 = 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;
+ what.step_resume = 0;
+ }
+
+#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 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 via the
+ cleanup chain, so no need to worry about it here. */
+ goto stop_stepping;
+
+ case BPSTAT_WHAT_KEEP_CHECKING:
+ break;
+ }
+
+ if (what.step_resume)
+ {
+ delete_breakpoint (step_resume_breakpoint);
+ step_resume_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;
+ }
+ }
+
+ /* 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 suspect this could/should be keep_going, because if the
+ check_sigtramp2 check succeeds, then it will put in another
+ step_resume_breakpoint, and we aren't (yet) prepared to nest
+ them. */
+ 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))
+ {
+ /* This code is needed at least in the following case:
+ The user types "next" and then a signal arrives (before
+ the "next" is done). */
+ /* We've just taken a signal; go until we are back to
+ the point where we took it and one more. */
+ {
+ struct symtab_and_line sr_sal;
+
+ sr_sal.pc = prev_pc;
+ sr_sal.symtab = NULL;
+ sr_sal.line = 0;
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, get_current_frame (),
+ 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 (stop_func_start)
+ {
+ /* Do this after the IN_SIGTRAMP check; it might give
+ an error. */
+ prologue_pc = stop_func_start;
+ 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
+
+#if 0
+ /* Not conservative enough for 4.11. FIXME: enable this
+ after 4.11. */
+ /* Except on the Alpha with -O (and perhaps other machines
+ with similar calling conventions), 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
+#endif
+
+ /* 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. */
+ ))
+ {
+ /* 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);
+ 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. */
+ 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.
+ 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)
+ 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 (but haven't done a
+ subroutine call or return). (Is that true? I think we get
+ here if we did a return and maybe a longjmp). */
+
+ 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)
+ {
+ /* 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.) */
+ 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;
+ step_resume_breakpoint =
+ set_momentary_breakpoint (sr_sal, get_current_frame (),
+ bp_step_resume);
+ 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;
+
+ /* If we did not do break;, it means we should keep
+ running the inferior and not return to debugger. */
+
+ if (trap_expected && stop_signal != SIGTRAP)
+ {
+ /* 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 &&
+ remove_breakpoints_on_following_step)
+ {
+ remove_breakpoints_on_following_step = 0;
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+ }
+ else if (!breakpoints_inserted &&
+ (step_resume_breakpoint != NULL || !another_trap))
+ {
+ breakpoints_failed = insert_breakpoints ();
+ if (breakpoints_failed)
+ break;
+ breakpoints_inserted = 1;
+ }
+
+ trap_expected = another_trap;
+
+ if (stop_signal == SIGTRAP)
+ stop_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 != SIGCLD)
+ && !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;
+ }
+ 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)
+ return;
+
+ 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)
+ return;
+
+ /* 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)
+ {
+ select_frame (get_current_frame (), 0);
+
+ 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;
+ select_frame (get_current_frame (), 0);
+ }
+}
+
+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 ((signo >= 0 && signo < NSIG) ? signal_stop[signo] : 0);
+}
+
+int signal_print_state (signo)
+ int signo;
+{
+ return ((signo >= 0 && signo < NSIG) ? signal_print[signo] : 0);
+}
+
+int signal_pass_state (signo)
+ int signo;
+{
+ return ((signo >= 0 && signo < NSIG) ? signal_program[signo] : 0);
+}
+
+static void
+sig_print_header ()
+{
+ printf_filtered ("Signal\t\tStop\tPrint\tPass to program\tDescription\n");
+}
+
+static void
+sig_print_info (number)
+ int number;
+{
+ char *name;
+
+ if ((name = strsigno (number)) == NULL)
+ printf_filtered ("%d\t\t", number);
+ else
+ printf_filtered ("%s (%d)\t", name, number);
+ printf_filtered ("%s\t", signal_stop[number] ? "Yes" : "No");
+ printf_filtered ("%s\t", signal_print[number] ? "Yes" : "No");
+ printf_filtered ("%s\t\t", signal_program[number] ? "Yes" : "No");
+ printf_filtered ("%s\n", safe_strsignal (number));
+}
+
+/* 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;
+ 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 = signo_max () + 1;
+ 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 numbers, 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)
+ {
+ 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 if ((signum = strtosigno (*argv)) != 0)
+ {
+ sigfirst = siglast = signum;
+ }
+ 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 (signum)
+ {
+ case SIGTRAP:
+ case SIGINT:
+ if (!allsigs && !sigs[signum])
+ {
+ if (query ("%s is used by the debugger.\nAre you sure you want to change it? ", strsigno (signum)))
+ {
+ sigs[signum] = 1;
+ }
+ else
+ {
+ printf ("Not confirmed, unchanged.\n");
+ fflush (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. */
+
+static void
+signals_info (signum_exp, from_tty)
+ char *signum_exp;
+ int from_tty;
+{
+ register int i;
+ sig_print_header ();
+
+ if (signum_exp)
+ {
+ /* First see if this is a symbol name. */
+ i = strtosigno (signum_exp);
+ if (i == 0)
+ {
+ /* Nope, maybe it's an address which evaluates to a signal
+ number. */
+ i = parse_and_eval_address (signum_exp);
+ if (i >= NSIG || i < 0)
+ error ("Signal number out of bounds.");
+ }
+ sig_print_info (i);
+ return;
+ }
+
+ printf_filtered ("\n");
+ for (i = 0; i < NSIG; i++)
+ {
+ QUIT;
+
+ sig_print_info (i);
+ }
+
+ 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 = signo_max () + 1;
+ 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[SIGTRAP] = 0;
+ signal_program[SIGINT] = 0;
+
+ /* Signals that are not errors should not normally enter the debugger. */
+#ifdef SIGALRM
+ signal_stop[SIGALRM] = 0;
+ signal_print[SIGALRM] = 0;
+#endif /* SIGALRM */
+#ifdef SIGVTALRM
+ signal_stop[SIGVTALRM] = 0;
+ signal_print[SIGVTALRM] = 0;
+#endif /* SIGVTALRM */
+#ifdef SIGPROF
+ signal_stop[SIGPROF] = 0;
+ signal_print[SIGPROF] = 0;
+#endif /* SIGPROF */
+#ifdef SIGCHLD
+ signal_stop[SIGCHLD] = 0;
+ signal_print[SIGCHLD] = 0;
+#endif /* SIGCHLD */
+#ifdef SIGCLD
+ signal_stop[SIGCLD] = 0;
+ signal_print[SIGCLD] = 0;
+#endif /* SIGCLD */
+#ifdef SIGIO
+ signal_stop[SIGIO] = 0;
+ signal_print[SIGIO] = 0;
+#endif /* SIGIO */
+#ifdef SIGURG
+ signal_stop[SIGURG] = 0;
+ signal_print[SIGURG] = 0;
+#endif /* SIGURG */
+}
diff --git a/gnu/usr.bin/gdb/gdb/inftarg.c b/gnu/usr.bin/gdb/gdb/inftarg.c
new file mode 100644
index 0000000..f937be4
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/inftarg.c
@@ -0,0 +1,310 @@
+/* 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 <signal.h>
+
+static void
+child_prepare_to_store PARAMS ((void));
+
+#ifndef CHILD_WAIT
+static int
+child_wait PARAMS ((int, int *));
+#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 STATUS. */
+
+static int
+child_wait (pid, status)
+ int pid;
+ int *status;
+{
+ int save_errno;
+
+ do {
+ if (attach_flag)
+ set_sigint_trap(); /* Causes SIGINT to be passed on to the
+ attached process. */
+ pid = wait (status);
+ save_errno = errno;
+
+ if (attach_flag)
+ clear_sigint_trap();
+
+ if (pid == -1)
+ {
+ if (save_errno == EINTR)
+ continue;
+ fprintf (stderr, "Child process unexpectedly missing: %s.\n",
+ safe_strerror (save_errno));
+ *status = 42; /* Claim it exited with signal 42 */
+ return -1;
+ }
+ } while (pid != inferior_pid); /* Some other child died or stopped */
+ 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;
+{
+ char *exec_file;
+ int pid;
+
+ if (!args)
+ error_no_arg ("process-id to attach");
+
+#ifndef ATTACH_DETACH
+ error ("Can't attach to a process on this machine.");
+#else
+ 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 ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid));
+ else
+ printf ("Attaching to %s\n", target_pid_to_str (pid));
+
+ fflush (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;
+{
+ int siggnal = 0;
+
+#ifdef ATTACH_DETACH
+ if (from_tty)
+ {
+ char *exec_file = get_exec_file (0);
+ if (exec_file == 0)
+ exec_file = "";
+ printf ("Detaching from program: %s %s\n", exec_file,
+ target_pid_to_str (inferior_pid));
+ fflush (stdout);
+ }
+ if (args)
+ siggnal = atoi (args);
+
+ detach (siggnal);
+ inferior_pid = 0;
+ unpush_target (&child_ops); /* Pop out of handling an inferior */
+#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 ("\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);
+}
+
+/* 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);
+ /* We are at the first instruction we care about. */
+ /* Pedal to the metal... */
+ proceed ((CORE_ADDR) -1, 0, 0);
+}
+
+static void
+child_mourn_inferior ()
+{
+ unpush_target (&child_ops);
+ 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..26afe1d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/init.c
@@ -0,0 +1,47 @@
+/* Do not modify this file. It is created automatically by "munch". */
+void initialize_all_files () {
+ {extern void _initialize_blockframe (); _initialize_blockframe ();}
+ {extern void _initialize_breakpoint (); _initialize_breakpoint ();}
+ {extern void _initialize_buildsym (); _initialize_buildsym ();}
+ {extern void _initialize_c_language (); _initialize_c_language ();}
+ {extern void _initialize_chill_language (); _initialize_chill_language ();}
+ {extern void _initialize_coffread (); _initialize_coffread ();}
+ {extern void _initialize_command (); _initialize_command ();}
+ {extern void _initialize_complaints (); _initialize_complaints ();}
+ {extern void _initialize_copying (); _initialize_copying ();}
+ {extern void _initialize_core (); _initialize_core ();}
+ {extern void _initialize_corelow (); _initialize_corelow ();}
+ {extern void _initialize_cp_valprint (); _initialize_cp_valprint ();}
+ {extern void _initialize_dbxread (); _initialize_dbxread ();}
+ {extern void _initialize_demangler (); _initialize_demangler ();}
+ {extern void _initialize_elfread (); _initialize_elfread ();}
+ {extern void _initialize_exec (); _initialize_exec ();}
+ {extern void _initialize_gdbtypes (); _initialize_gdbtypes ();}
+ {extern void _initialize_infcmd (); _initialize_infcmd ();}
+ {extern void _initialize_inflow (); _initialize_inflow ();}
+ {extern void _initialize_infrun (); _initialize_infrun ();}
+ {extern void _initialize_inftarg (); _initialize_inftarg ();}
+ {extern void _initialize_language (); _initialize_language ();}
+ {extern void _initialize_m2_language (); _initialize_m2_language ();}
+ {extern void _initialize_maint_cmds (); _initialize_maint_cmds ();}
+ {extern void _initialize_mipsread (); _initialize_mipsread ();}
+ {extern void _initialize_nlmread (); _initialize_nlmread ();}
+ {extern void _initialize_parse (); _initialize_parse ();}
+ {extern void _initialize_printcmd (); _initialize_printcmd ();}
+ {extern void _initialize_remote (); _initialize_remote ();}
+ {extern void _initialize_ser_hardwire (); _initialize_ser_hardwire ();}
+ {extern void _initialize_solib (); _initialize_solib ();}
+ {extern void _initialize_source (); _initialize_source ();}
+ {extern void _initialize_sr_support (); _initialize_sr_support ();}
+ {extern void _initialize_stabsread (); _initialize_stabsread ();}
+ {extern void _initialize_stack (); _initialize_stack ();}
+ {extern void _initialize_symfile (); _initialize_symfile ();}
+ {extern void _initialize_symmisc (); _initialize_symmisc ();}
+ {extern void _initialize_symtab (); _initialize_symtab ();}
+ {extern void _initialize_targets (); _initialize_targets ();}
+ {extern void _initialize_thread (); _initialize_thread ();}
+ {extern void _initialize_typeprint (); _initialize_typeprint ();}
+ {extern void _initialize_utils (); _initialize_utils ();}
+ {extern void _initialize_valprint (); _initialize_valprint ();}
+ {extern void _initialize_values (); _initialize_values ();}
+}
diff --git a/gnu/usr.bin/gdb/gdb/language.c b/gnu/usr.bin/gdb/gdb/language.c
new file mode 100644
index 0000000..be51953
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/language.c
@@ -0,0 +1,1332 @@
+/* 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("The currently understood settings are:\n\n");
+ printf ("local or auto Automatic setting based on source file\n");
+ printf ("c Use the C language\n");
+ printf ("c++ Use the C++ language\n");
+ printf ("chill Use the Chill language\n");
+ printf ("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(
+"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(
+"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("Current language: %s\n",language);
+ show_language_command((char *)0, 1);
+
+ if (!quietly)
+ {
+ printf("Type checking: %s\n",type);
+ show_type_command((char *)0, 1);
+ printf("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 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;
+{
+ switch(current_language->la_language)
+ {
+ case language_chill:
+ case language_m2:
+ return TYPE_CODE(type) != TYPE_CODE_BOOL ? 0 : 1;
+
+ case language_c:
+ case language_cplus:
+ return TYPE_CODE(type) != TYPE_CODE_INT ? 0 : 1;
+ default:
+ 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 val;
+{
+ int len, i;
+ struct type *type;
+ LONGEST v;
+
+ switch (current_language->la_language) {
+
+ case language_c:
+ case language_cplus:
+ return !value_logical_not (val);
+
+ case language_m2:
+ type = VALUE_TYPE(val);
+ if (TYPE_CODE (type) != TYPE_CODE_BOOL)
+ return 0; /* Not a BOOLEAN at all */
+ /* Search the fields for one that matches the current value. */
+ len = TYPE_NFIELDS (type);
+ v = value_as_long (val);
+ for (i = 0; i < len; i++)
+ {
+ QUIT;
+ if (v == TYPE_FIELD_BITPOS (type, i))
+ break;
+ }
+ if (i >= len)
+ return 0; /* Not a valid BOOLEAN value */
+ if (STREQ ("TRUE", TYPE_FIELD_NAME(VALUE_TYPE(val), i)))
+ return 1; /* BOOLEAN with value TRUE */
+ else
+ return 0; /* BOOLEAN with value FALSE */
+ break;
+
+ case language_chill:
+ error ("Missing Chill support in function value_type."); /*FIXME*/
+
+ default:
+ error ("Language not supported.");
+ }
+}
+
+/* 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 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!=(value)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(stderr,warning_pre_print);
+ else
+ target_terminal_ours();
+
+ va_start (args);
+ string = va_arg (args, char *);
+ vfprintf (stderr, string, args);
+ fprintf (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(stderr,warning_pre_print);
+ else
+ target_terminal_ours();
+
+ va_start (args);
+ string = va_arg (args, char *);
+ vfprintf (stderr, string, args);
+ fprintf (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(
+"\"set check\" must be followed by the name of a check subcommand.\n");
+ help_list(setchecklist, "set check ", -1, 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(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;
+ FILE *stream;
+{
+ error ("internal error - unimplemented function unk_lang_printchar called.");
+}
+
+static void
+unk_lang_printstr (stream, string, length, force_ellipses)
+ 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;
+ 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;
+ FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ error ("internal error - unimplemented function unk_lang_val_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 */
+ &builtin_type_error, /* longest signed integral type */
+ &builtin_type_error, /* longest unsigned integral type */
+ &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 */
+ &builtin_type_error, /* longest signed integral type */
+ &builtin_type_error, /* longest unsigned integral type */
+ &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 */
+ &builtin_type_error, /* longest signed integral type */
+ &builtin_type_error, /* longest unsigned integral type */
+ &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..9df5345
--- /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 */
+
+ 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, FILE *));
+
+ void (*la_printstr) PARAMS ((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 *, FILE *, int, int));
+
+ /* Print a value using syntax appropriate for this language. */
+
+ int (*la_val_print) PARAMS ((struct type *, char *, CORE_ADDR, FILE *,
+ int, int, int, enum val_prettyprint));
+
+ /* Longest signed integral type */
+
+ struct type **la_longest_int;
+
+ /* Longest unsigned integral type */
+
+ struct type **la_longest_unsigned_int;
+
+ /* 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_int() (*current_language->la_longest_int)
+#define longest_unsigned_int() (*current_language->la_longest_unsigned_int)
+#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))
+
+/* 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/m2-exp.tab.c b/gnu/usr.bin/gdb/gdb/m2-exp.tab.c
new file mode 100644
index 0000000..53b1385
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/m2-exp.tab.c
@@ -0,0 +1,1991 @@
+#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 yyparse m2_parse
+#define yylex m2_lex
+#define yyerror m2_error
+#define yychar m2_char
+#define yyval m2_val
+#define yylval m2_lval
+#define yydebug m2_debug
+#define yynerrs m2_nerrs
+#define yyerrflag m2_errflag
+#define yyss m2_ss
+#define yyssp m2_ssp
+#define yyvs m2_vs
+#define yyvsp m2_vsp
+#define yylhs m2_lhs
+#define yylen m2_len
+#define yydefred m2_defred
+#define yydgoto m2_dgoto
+#define yysindex m2_sindex
+#define yyrindex m2_rindex
+#define yygindex m2_gindex
+#define yytable m2_table
+#define yycheck m2_check
+#define yyname m2_name
+#define yyrule m2_rule
+#define YYPREFIX "m2_"
+#line 40 "./m2-exp.y"
+
+#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
+
+#line 121 "./m2-exp.y"
+typedef 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;
+ } YYSTYPE;
+#line 129 "y.tab.c"
+#define INT 257
+#define HEX 258
+#define ERROR 259
+#define UINT 260
+#define M2_TRUE 261
+#define M2_FALSE 262
+#define CHAR 263
+#define FLOAT 264
+#define STRING 265
+#define NAME 266
+#define BLOCKNAME 267
+#define IDENT 268
+#define VARNAME 269
+#define TYPENAME 270
+#define SIZE 271
+#define CAP 272
+#define ORD 273
+#define HIGH 274
+#define ABS 275
+#define MIN_FUNC 276
+#define MAX_FUNC 277
+#define FLOAT_FUNC 278
+#define VAL 279
+#define CHR 280
+#define ODD 281
+#define TRUNC 282
+#define INC 283
+#define DEC 284
+#define INCL 285
+#define EXCL 286
+#define COLONCOLON 287
+#define LAST 288
+#define REGNAME 289
+#define INTERNAL_VAR 290
+#define ABOVE_COMMA 291
+#define ASSIGN 292
+#define LEQ 293
+#define GEQ 294
+#define NOTEQUAL 295
+#define IN 296
+#define OROR 297
+#define LOGICAL_AND 298
+#define DIV 299
+#define MOD 300
+#define UNARY 301
+#define DOT 302
+#define NOT 303
+#define QID 304
+#define YYERRCODE 256
+short m2_lhs[] = { -1,
+ 0, 0, 2, 1, 8, 1, 1, 1, 9, 9,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3, 3, 12, 1, 13, 1, 10, 10, 10,
+ 11, 11, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 6, 7, 7, 4, 4, 4, 4,
+ 5,
+};
+short m2_len[] = { 2,
+ 1, 1, 1, 2, 0, 3, 2, 2, 1, 1,
+ 4, 4, 4, 4, 4, 4, 4, 6, 4, 4,
+ 4, 2, 4, 6, 4, 6, 3, 1, 3, 6,
+ 6, 3, 4, 0, 5, 0, 5, 0, 1, 3,
+ 1, 3, 4, 4, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 4, 1, 1, 1, 3, 1, 1, 3, 1,
+ 1,
+};
+short m2_defred[] = { 0,
+ 65, 66, 63, 64, 67, 68, 73, 80, 75, 81,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 70, 71, 78, 0,
+ 5, 0, 9, 10, 0, 0, 0, 2, 28, 69,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 4, 0, 34, 36,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 45, 0, 0, 32, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 29, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 27, 0, 0, 0, 0,
+ 79, 76, 72, 11, 12, 14, 13, 15, 16, 17,
+ 0, 19, 20, 21, 0, 23, 0, 25, 0, 0,
+ 0, 0, 0, 0, 0, 44, 33, 0, 0, 0,
+ 0, 0, 0, 35, 37, 18, 24, 26, 30, 31,
+ 0,
+};
+short m2_dgoto[] = { 36,
+ 66, 38, 39, 40, 47, 42, 43, 64, 44, 68,
+ 164, 137, 138,
+};
+short m2_sindex[] = { 1597,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1779, -27, -21, -15, -10, -6, -3, -2, 18, 20,
+ 24, 31, 38, 39, 59, 77, 0, 0, 0, 1597,
+ 0, 1597, 0, 0, 1597, 0, 1670, 0, 0, 0,
+ -26, -256, 0, 1597, 1597, -24, -26, 1597, 1597, 1597,
+ 1597, -218, -218, 1597, -218, 1597, 1597, 1597, 1597, 1597,
+ 1597, 1597, -24, 1597, 939, 1670, -37, -17, 1597, 1597,
+ 1597, 1597, 1597, 1597, 1597, 1597, -118, 1597, 1597, 1597,
+ 1597, 1597, 1597, 1597, 1597, 1597, 0, -186, 0, 0,
+ 1597, 1597, -259, -24, -30, 967, 1002, 1044, 1079, 78,
+ 83, 1160, 74, 1268, 1323, 1351, 866, 894, 1183, 1404,
+ -24, 0, 1597, 1597, 0, 1727, -25, -25, -25, -25,
+ -25, -25, -25, 1597, 0, 8, 80, 192, 117, 49,
+ 49, -24, -24, -24, -24, 0, 1597, 1597, 1449, -11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1597, 0, 0, 0, 1597, 0, 1597, 0, 1597, 1597,
+ -24, 1670, 1670, -44, -20, 0, 0, 1484, 1512, 1547,
+ 1617, 1628, 1597, 0, 0, 0, 0, 0, 0, 0,
+ 1670,
+};
+short m2_rindex[] = { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, -9, 0, 121, 0, 0, 0,
+ 135, 0, 1, 0, 0, 12, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 40, 0, 0, -35, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, -9, 0, 68, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 106, 0, 0, 0, 0, 98, 568, 575, 598, 653,
+ 677, 779, 838, -9, 0, 0, 561, 539, 502, 465,
+ 489, 134, 145, 220, 411, 0, 0, -12, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 435, -18, -42, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -16,
+};
+short m2_gindex[] = { 0,
+ 2066, 0, 61, 0, 341, 0, 0, 0, 0, -88,
+ 0, 0, 0,
+};
+#define YYTABLESIZE 2239
+short m2_table[] = { 173,
+ 77, 41, 91, 140, 124, 39, 141, 142, 39, 91,
+ 143, 22, 48, 91, 90, 90, 83, 81, 49, 82,
+ 175, 84, 40, 114, 50, 40, 114, 42, 38, 51,
+ 93, 38, 114, 52, 38, 77, 53, 54, 80, 7,
+ 77, 77, 77, 77, 77, 77, 22, 77, 174, 165,
+ 41, 10, 22, 22, 22, 22, 22, 55, 22, 56,
+ 77, 77, 77, 57, 77, 89, 89, 8, 87, 87,
+ 58, 22, 22, 22, 7, 22, 42, 59, 60, 136,
+ 7, 7, 7, 7, 7, 92, 7, 113, 90, 39,
+ 83, 77, 92, 77, 77, 84, 92, 62, 61, 7,
+ 7, 7, 8, 7, 22, 6, 40, 115, 8, 8,
+ 8, 8, 8, 167, 8, 38, 62, 151, 148, 90,
+ 1, 83, 81, 149, 82, 77, 84, 8, 8, 8,
+ 92, 8, 7, 47, 3, 0, 22, 125, 62, 89,
+ 6, 62, 87, 80, 48, 0, 6, 6, 6, 6,
+ 6, 10, 6, 0, 0, 0, 90, 0, 83, 81,
+ 8, 82, 0, 84, 7, 6, 6, 6, 47, 6,
+ 89, 0, 0, 87, 47, 47, 47, 47, 47, 48,
+ 47, 0, 0, 0, 0, 48, 48, 48, 48, 48,
+ 62, 48, 8, 47, 47, 47, 0, 47, 6, 0,
+ 0, 0, 0, 0, 48, 48, 48, 89, 48, 0,
+ 87, 0, 0, 0, 0, 0, 0, 0, 0, 49,
+ 0, 0, 62, 0, 0, 0, 47, 0, 0, 0,
+ 6, 90, 0, 83, 81, 0, 82, 48, 84, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 49, 80, 0, 0, 47, 0,
+ 49, 49, 49, 49, 49, 0, 49, 0, 0, 48,
+ 0, 78, 79, 85, 86, 0, 88, 88, 0, 49,
+ 49, 49, 89, 49, 0, 87, 0, 74, 0, 0,
+ 0, 0, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 0, 77, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 49, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 41, 0, 0, 0, 49, 0, 0, 85, 86, 0,
+ 88, 0, 0, 0, 0, 0, 0, 0, 0, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0,
+ 0, 0, 0, 0, 0, 67, 0, 79, 85, 86,
+ 0, 88, 0, 0, 0, 95, 0, 0, 0, 0,
+ 0, 0, 100, 101, 0, 103, 0, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 0, 0, 0, 0,
+ 50, 0, 0, 0, 0, 85, 86, 126, 88, 0,
+ 0, 0, 0, 0, 0, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 43, 0, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 50, 0, 0, 0, 0,
+ 0, 50, 50, 50, 50, 50, 0, 50, 0, 0,
+ 0, 0, 0, 0, 51, 0, 0, 0, 0, 43,
+ 50, 50, 50, 0, 50, 43, 43, 43, 43, 43,
+ 0, 43, 0, 0, 0, 0, 0, 0, 52, 0,
+ 85, 86, 0, 88, 43, 43, 43, 0, 43, 51,
+ 0, 46, 0, 50, 0, 51, 0, 51, 51, 51,
+ 0, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+ 0, 0, 0, 52, 51, 51, 51, 43, 51, 52,
+ 0, 52, 52, 52, 0, 50, 46, 0, 60, 0,
+ 0, 0, 46, 0, 0, 46, 0, 0, 52, 52,
+ 52, 0, 52, 0, 0, 0, 0, 51, 0, 43,
+ 61, 46, 46, 46, 0, 46, 0, 58, 0, 0,
+ 0, 0, 0, 60, 59, 0, 0, 0, 0, 60,
+ 0, 52, 60, 0, 0, 0, 0, 0, 0, 51,
+ 0, 0, 0, 0, 46, 61, 0, 56, 60, 60,
+ 60, 61, 58, 0, 61, 0, 0, 0, 58, 59,
+ 0, 58, 0, 52, 0, 59, 0, 0, 59, 0,
+ 61, 61, 61, 0, 0, 0, 46, 58, 58, 58,
+ 0, 60, 56, 0, 59, 59, 59, 0, 56, 0,
+ 0, 56, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 57, 61, 0, 0, 0, 56, 56, 56,
+ 58, 0, 0, 60, 0, 0, 0, 59, 0, 0,
+ 0, 0, 0, 0, 0, 0, 53, 0, 0, 0,
+ 0, 0, 0, 0, 0, 61, 0, 57, 0, 0,
+ 56, 0, 58, 57, 0, 0, 57, 0, 0, 59,
+ 0, 0, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 53, 57, 57, 57, 0, 0, 53, 0, 0,
+ 53, 0, 56, 0, 0, 0, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 0, 53, 53, 53, 0,
+ 0, 0, 0, 0, 0, 57, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 51, 51, 51, 51,
+ 51, 51, 51, 0, 0, 0, 0, 0, 0, 53,
+ 0, 0, 0, 0, 0, 0, 0, 57, 54, 0,
+ 52, 52, 52, 52, 52, 52, 52, 0, 0, 0,
+ 0, 0, 0, 46, 46, 46, 46, 46, 46, 46,
+ 0, 53, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 54, 0, 0, 0, 0, 0, 54,
+ 0, 0, 54, 0, 0, 0, 0, 0, 0, 0,
+ 60, 60, 60, 60, 60, 60, 60, 55, 54, 54,
+ 54, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 61, 61, 61, 61, 61, 61, 0, 58,
+ 58, 58, 58, 58, 0, 0, 59, 59, 59, 59,
+ 59, 54, 55, 0, 0, 0, 0, 0, 55, 0,
+ 0, 55, 0, 0, 0, 0, 0, 0, 0, 56,
+ 56, 56, 56, 56, 0, 0, 0, 55, 55, 55,
+ 76, 0, 0, 54, 0, 90, 156, 83, 81, 155,
+ 82, 0, 84, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 70, 74, 71, 76, 80,
+ 55, 0, 0, 90, 158, 83, 81, 157, 82, 0,
+ 84, 0, 0, 0, 57, 57, 57, 57, 57, 0,
+ 0, 0, 0, 70, 74, 71, 89, 80, 0, 87,
+ 0, 0, 55, 0, 0, 0, 0, 0, 53, 53,
+ 53, 53, 53, 76, 0, 0, 0, 0, 90, 112,
+ 83, 81, 0, 82, 89, 84, 0, 87, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 70, 74,
+ 71, 76, 80, 0, 0, 0, 90, 144, 83, 81,
+ 0, 82, 0, 84, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 70, 74, 71, 89,
+ 80, 0, 87, 0, 0, 0, 76, 0, 0, 0,
+ 0, 90, 145, 83, 81, 0, 82, 0, 84, 0,
+ 0, 0, 0, 0, 0, 0, 0, 89, 0, 0,
+ 87, 70, 74, 71, 0, 80, 0, 0, 0, 0,
+ 54, 54, 54, 54, 54, 0, 0, 0, 76, 0,
+ 0, 0, 0, 90, 146, 83, 81, 0, 82, 0,
+ 84, 0, 89, 0, 0, 87, 0, 0, 0, 0,
+ 0, 0, 0, 70, 74, 71, 0, 80, 0, 0,
+ 0, 0, 0, 76, 0, 0, 0, 0, 90, 147,
+ 83, 81, 0, 82, 0, 84, 0, 0, 0, 55,
+ 55, 55, 55, 55, 89, 0, 0, 87, 70, 74,
+ 71, 0, 80, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 69, 72, 73,
+ 75, 77, 78, 79, 85, 86, 0, 88, 0, 89,
+ 0, 0, 87, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 69, 72, 73, 75, 77,
+ 78, 79, 85, 86, 76, 88, 0, 0, 0, 90,
+ 150, 83, 81, 0, 82, 0, 84, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 76, 0, 70,
+ 74, 71, 90, 80, 83, 81, 159, 82, 0, 84,
+ 69, 72, 73, 75, 77, 78, 79, 85, 86, 0,
+ 88, 0, 70, 74, 71, 0, 80, 0, 0, 0,
+ 89, 0, 0, 87, 0, 0, 0, 0, 69, 72,
+ 73, 75, 77, 78, 79, 85, 86, 0, 88, 0,
+ 0, 0, 0, 89, 0, 0, 87, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 69, 72, 73, 75, 77, 78, 79,
+ 85, 86, 76, 88, 0, 0, 0, 90, 152, 83,
+ 81, 0, 82, 0, 84, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 70, 74, 71,
+ 0, 80, 0, 0, 0, 69, 72, 73, 75, 77,
+ 78, 79, 85, 86, 0, 88, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 76, 89, 0,
+ 0, 87, 90, 153, 83, 81, 0, 82, 0, 84,
+ 69, 72, 73, 75, 77, 78, 79, 85, 86, 0,
+ 88, 0, 70, 74, 71, 76, 80, 0, 0, 0,
+ 90, 154, 83, 81, 0, 82, 0, 84, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 70, 74, 71, 89, 80, 0, 87, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 76, 0,
+ 0, 89, 0, 90, 87, 83, 81, 160, 82, 0,
+ 84, 69, 72, 73, 75, 77, 78, 79, 85, 86,
+ 0, 88, 0, 70, 74, 71, 0, 80, 0, 0,
+ 0, 0, 0, 0, 69, 72, 73, 75, 77, 78,
+ 79, 85, 86, 76, 88, 0, 0, 0, 90, 166,
+ 83, 81, 0, 82, 89, 84, 0, 87, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 70, 74,
+ 71, 0, 80, 0, 0, 0, 0, 0, 76, 0,
+ 0, 0, 0, 90, 176, 83, 81, 0, 82, 0,
+ 84, 0, 0, 0, 0, 0, 0, 0, 0, 89,
+ 0, 0, 87, 70, 74, 71, 76, 80, 0, 0,
+ 0, 90, 177, 83, 81, 0, 82, 0, 84, 69,
+ 72, 73, 75, 77, 78, 79, 85, 86, 0, 88,
+ 0, 70, 74, 71, 89, 80, 0, 87, 0, 0,
+ 0, 76, 0, 0, 0, 0, 90, 178, 83, 81,
+ 0, 82, 0, 84, 0, 0, 0, 0, 0, 0,
+ 0, 0, 89, 0, 0, 87, 70, 74, 71, 0,
+ 80, 0, 0, 0, 69, 72, 73, 75, 77, 78,
+ 79, 85, 86, 0, 88, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 32, 89, 0, 30,
+ 87, 31, 69, 72, 73, 75, 77, 78, 79, 85,
+ 86, 76, 88, 0, 0, 0, 90, 179, 83, 81,
+ 0, 82, 76, 84, 0, 0, 0, 90, 180, 83,
+ 81, 0, 82, 0, 84, 0, 70, 74, 71, 0,
+ 80, 0, 0, 0, 0, 0, 0, 70, 74, 71,
+ 0, 80, 0, 0, 0, 69, 72, 73, 75, 77,
+ 78, 79, 85, 86, 76, 88, 0, 89, 0, 90,
+ 87, 83, 81, 0, 82, 0, 84, 0, 89, 35,
+ 0, 87, 34, 0, 0, 0, 0, 0, 0, 70,
+ 74, 71, 0, 80, 0, 0, 0, 0, 0, 0,
+ 69, 72, 73, 75, 77, 78, 79, 85, 86, 0,
+ 88, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 89, 76, 0, 87, 0, 0, 90, 0, 83, 81,
+ 0, 82, 0, 84, 0, 69, 72, 73, 75, 77,
+ 78, 79, 85, 86, 0, 88, 70, 74, 71, 0,
+ 80, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 69, 72, 73, 75, 77, 78, 79,
+ 85, 86, 0, 88, 0, 0, 0, 89, 45, 0,
+ 87, 30, 0, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 69, 72,
+ 73, 75, 77, 78, 79, 85, 86, 0, 88, 0,
+ 0, 0, 0, 1, 0, 0, 2, 3, 4, 5,
+ 6, 7, 8, 9, 0, 0, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 0, 27, 28, 29, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 33,
+ 0, 35, 0, 0, 34, 0, 0, 0, 69, 72,
+ 73, 75, 77, 78, 79, 85, 86, 0, 88, 69,
+ 72, 73, 75, 77, 78, 79, 85, 86, 0, 88,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 69, 72, 73, 75, 77, 78, 79, 85, 86,
+ 0, 88, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 72,
+ 73, 75, 77, 78, 79, 85, 86, 0, 88, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 2, 3,
+ 4, 5, 6, 7, 8, 9, 0, 0, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 37, 27, 28, 29, 0,
+ 0, 0, 0, 0, 0, 0, 46, 0, 0, 0,
+ 0, 33, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 63, 0, 65, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 94,
+ 65, 0, 0, 96, 97, 98, 99, 0, 0, 102,
+ 0, 104, 105, 106, 107, 108, 109, 110, 0, 111,
+ 0, 0, 0, 0, 116, 117, 118, 119, 120, 121,
+ 122, 123, 0, 127, 128, 129, 130, 131, 132, 133,
+ 134, 135, 0, 0, 0, 0, 139, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 161, 162,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 163, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 168, 0, 0, 0,
+ 169, 0, 170, 0, 171, 172, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 181,
+};
+short m2_check[] = { 44,
+ 0, 44, 40, 92, 123, 41, 266, 267, 44, 40,
+ 41, 0, 40, 40, 40, 40, 42, 43, 40, 45,
+ 41, 47, 41, 44, 40, 44, 44, 44, 41, 40,
+ 287, 44, 44, 40, 44, 35, 40, 40, 64, 0,
+ 40, 41, 42, 43, 44, 45, 35, 47, 93, 138,
+ 93, 270, 41, 42, 43, 44, 45, 40, 47, 40,
+ 60, 61, 62, 40, 64, 91, 91, 0, 94, 94,
+ 40, 60, 61, 62, 35, 64, 93, 40, 40, 266,
+ 41, 42, 43, 44, 45, 123, 47, 125, 40, 125,
+ 42, 91, 123, 93, 94, 47, 123, 0, 40, 60,
+ 61, 62, 35, 64, 93, 0, 125, 125, 41, 42,
+ 43, 44, 45, 125, 47, 125, 40, 44, 41, 40,
+ 0, 42, 43, 41, 45, 125, 47, 60, 61, 62,
+ 123, 64, 93, 0, 0, -1, 125, 77, 41, 91,
+ 35, 44, 94, 64, 0, -1, 41, 42, 43, 44,
+ 45, 270, 47, -1, -1, -1, 40, -1, 42, 43,
+ 93, 45, -1, 47, 125, 60, 61, 62, 35, 64,
+ 91, -1, -1, 94, 41, 42, 43, 44, 45, 35,
+ 47, -1, -1, -1, -1, 41, 42, 43, 44, 45,
+ 93, 47, 125, 60, 61, 62, -1, 64, 93, -1,
+ -1, -1, -1, -1, 60, 61, 62, 91, 64, -1,
+ 94, -1, -1, -1, -1, -1, -1, -1, -1, 0,
+ -1, -1, 125, -1, -1, -1, 93, -1, -1, -1,
+ 125, 40, -1, 42, 43, -1, 45, 93, 47, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 35, 64, -1, -1, 125, -1,
+ 41, 42, 43, 44, 45, -1, 47, -1, -1, 125,
+ -1, 297, 298, 299, 300, -1, 302, 302, -1, 60,
+ 61, 62, 91, 64, -1, 94, -1, 287, -1, -1,
+ -1, -1, 292, 293, 294, 295, 296, 297, 298, 299,
+ 300, -1, 302, 292, 293, 294, 295, 296, 297, 298,
+ 299, 300, 93, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 292, 293, 294, 295, 296, 297, 298, 299, 300,
+ 0, -1, -1, -1, 125, -1, -1, 299, 300, -1,
+ 302, -1, -1, -1, -1, -1, -1, -1, -1, 292,
+ 293, 294, 295, 296, 297, 298, 299, 300, -1, -1,
+ -1, -1, -1, -1, -1, 35, -1, 298, 299, 300,
+ -1, 302, -1, -1, -1, 45, -1, -1, -1, -1,
+ -1, -1, 52, 53, -1, 55, -1, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, -1, -1, -1, -1,
+ 0, -1, -1, -1, -1, 299, 300, 77, 302, -1,
+ -1, -1, -1, -1, -1, 292, 293, 294, 295, 296,
+ 297, 298, 299, 300, 0, -1, 292, 293, 294, 295,
+ 296, 297, 298, 299, 300, 35, -1, -1, -1, -1,
+ -1, 41, 42, 43, 44, 45, -1, 47, -1, -1,
+ -1, -1, -1, -1, 0, -1, -1, -1, -1, 35,
+ 60, 61, 62, -1, 64, 41, 42, 43, 44, 45,
+ -1, 47, -1, -1, -1, -1, -1, -1, 0, -1,
+ 299, 300, -1, 302, 60, 61, 62, -1, 64, 35,
+ -1, 0, -1, 93, -1, 41, -1, 43, 44, 45,
+ -1, 292, 293, 294, 295, 296, 297, 298, 299, 300,
+ -1, -1, -1, 35, 60, 61, 62, 93, 64, 41,
+ -1, 43, 44, 45, -1, 125, 35, -1, 0, -1,
+ -1, -1, 41, -1, -1, 44, -1, -1, 60, 61,
+ 62, -1, 64, -1, -1, -1, -1, 93, -1, 125,
+ 0, 60, 61, 62, -1, 64, -1, 0, -1, -1,
+ -1, -1, -1, 35, 0, -1, -1, -1, -1, 41,
+ -1, 93, 44, -1, -1, -1, -1, -1, -1, 125,
+ -1, -1, -1, -1, 93, 35, -1, 0, 60, 61,
+ 62, 41, 35, -1, 44, -1, -1, -1, 41, 35,
+ -1, 44, -1, 125, -1, 41, -1, -1, 44, -1,
+ 60, 61, 62, -1, -1, -1, 125, 60, 61, 62,
+ -1, 93, 35, -1, 60, 61, 62, -1, 41, -1,
+ -1, 44, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 0, 93, -1, -1, -1, 60, 61, 62,
+ 93, -1, -1, 125, -1, -1, -1, 93, -1, -1,
+ -1, -1, -1, -1, -1, -1, 0, -1, -1, -1,
+ -1, -1, -1, -1, -1, 125, -1, 35, -1, -1,
+ 93, -1, 125, 41, -1, -1, 44, -1, -1, 125,
+ -1, -1, 292, 293, 294, 295, 296, 297, 298, 299,
+ 300, 35, 60, 61, 62, -1, -1, 41, -1, -1,
+ 44, -1, 125, -1, -1, -1, 292, 293, 294, 295,
+ 296, 297, 298, 299, 300, -1, 60, 61, 62, -1,
+ -1, -1, -1, -1, -1, 93, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 292, 293, 294, 295,
+ 296, 297, 298, -1, -1, -1, -1, -1, -1, 93,
+ -1, -1, -1, -1, -1, -1, -1, 125, 0, -1,
+ 292, 293, 294, 295, 296, 297, 298, -1, -1, -1,
+ -1, -1, -1, 292, 293, 294, 295, 296, 297, 298,
+ -1, 125, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 35, -1, -1, -1, -1, -1, 41,
+ -1, -1, 44, -1, -1, -1, -1, -1, -1, -1,
+ 292, 293, 294, 295, 296, 297, 298, 0, 60, 61,
+ 62, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 292, 293, 294, 295, 296, 297, -1, 292,
+ 293, 294, 295, 296, -1, -1, 292, 293, 294, 295,
+ 296, 93, 35, -1, -1, -1, -1, -1, 41, -1,
+ -1, 44, -1, -1, -1, -1, -1, -1, -1, 292,
+ 293, 294, 295, 296, -1, -1, -1, 60, 61, 62,
+ 35, -1, -1, 125, -1, 40, 41, 42, 43, 44,
+ 45, -1, 47, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 60, 61, 62, 35, 64,
+ 93, -1, -1, 40, 41, 42, 43, 44, 45, -1,
+ 47, -1, -1, -1, 292, 293, 294, 295, 296, -1,
+ -1, -1, -1, 60, 61, 62, 91, 64, -1, 94,
+ -1, -1, 125, -1, -1, -1, -1, -1, 292, 293,
+ 294, 295, 296, 35, -1, -1, -1, -1, 40, 41,
+ 42, 43, -1, 45, 91, 47, -1, 94, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 60, 61,
+ 62, 35, 64, -1, -1, -1, 40, 41, 42, 43,
+ -1, 45, -1, 47, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 60, 61, 62, 91,
+ 64, -1, 94, -1, -1, -1, 35, -1, -1, -1,
+ -1, 40, 41, 42, 43, -1, 45, -1, 47, -1,
+ -1, -1, -1, -1, -1, -1, -1, 91, -1, -1,
+ 94, 60, 61, 62, -1, 64, -1, -1, -1, -1,
+ 292, 293, 294, 295, 296, -1, -1, -1, 35, -1,
+ -1, -1, -1, 40, 41, 42, 43, -1, 45, -1,
+ 47, -1, 91, -1, -1, 94, -1, -1, -1, -1,
+ -1, -1, -1, 60, 61, 62, -1, 64, -1, -1,
+ -1, -1, -1, 35, -1, -1, -1, -1, 40, 41,
+ 42, 43, -1, 45, -1, 47, -1, -1, -1, 292,
+ 293, 294, 295, 296, 91, -1, -1, 94, 60, 61,
+ 62, -1, 64, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, -1, 302, -1, 91,
+ -1, -1, 94, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 292, 293, 294, 295, 296,
+ 297, 298, 299, 300, 35, 302, -1, -1, -1, 40,
+ 41, 42, 43, -1, 45, -1, 47, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 35, -1, 60,
+ 61, 62, 40, 64, 42, 43, 44, 45, -1, 47,
+ 292, 293, 294, 295, 296, 297, 298, 299, 300, -1,
+ 302, -1, 60, 61, 62, -1, 64, -1, -1, -1,
+ 91, -1, -1, 94, -1, -1, -1, -1, 292, 293,
+ 294, 295, 296, 297, 298, 299, 300, -1, 302, -1,
+ -1, -1, -1, 91, -1, -1, 94, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 292, 293, 294, 295, 296, 297, 298,
+ 299, 300, 35, 302, -1, -1, -1, 40, 41, 42,
+ 43, -1, 45, -1, 47, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 60, 61, 62,
+ -1, 64, -1, -1, -1, 292, 293, 294, 295, 296,
+ 297, 298, 299, 300, -1, 302, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 35, 91, -1,
+ -1, 94, 40, 41, 42, 43, -1, 45, -1, 47,
+ 292, 293, 294, 295, 296, 297, 298, 299, 300, -1,
+ 302, -1, 60, 61, 62, 35, 64, -1, -1, -1,
+ 40, 41, 42, 43, -1, 45, -1, 47, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 60, 61, 62, 91, 64, -1, 94, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 35, -1,
+ -1, 91, -1, 40, 94, 42, 43, 44, 45, -1,
+ 47, 292, 293, 294, 295, 296, 297, 298, 299, 300,
+ -1, 302, -1, 60, 61, 62, -1, 64, -1, -1,
+ -1, -1, -1, -1, 292, 293, 294, 295, 296, 297,
+ 298, 299, 300, 35, 302, -1, -1, -1, 40, 41,
+ 42, 43, -1, 45, 91, 47, -1, 94, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 60, 61,
+ 62, -1, 64, -1, -1, -1, -1, -1, 35, -1,
+ -1, -1, -1, 40, 41, 42, 43, -1, 45, -1,
+ 47, -1, -1, -1, -1, -1, -1, -1, -1, 91,
+ -1, -1, 94, 60, 61, 62, 35, 64, -1, -1,
+ -1, 40, 41, 42, 43, -1, 45, -1, 47, 292,
+ 293, 294, 295, 296, 297, 298, 299, 300, -1, 302,
+ -1, 60, 61, 62, 91, 64, -1, 94, -1, -1,
+ -1, 35, -1, -1, -1, -1, 40, 41, 42, 43,
+ -1, 45, -1, 47, -1, -1, -1, -1, -1, -1,
+ -1, -1, 91, -1, -1, 94, 60, 61, 62, -1,
+ 64, -1, -1, -1, 292, 293, 294, 295, 296, 297,
+ 298, 299, 300, -1, 302, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 40, 91, -1, 43,
+ 94, 45, 292, 293, 294, 295, 296, 297, 298, 299,
+ 300, 35, 302, -1, -1, -1, 40, 41, 42, 43,
+ -1, 45, 35, 47, -1, -1, -1, 40, 41, 42,
+ 43, -1, 45, -1, 47, -1, 60, 61, 62, -1,
+ 64, -1, -1, -1, -1, -1, -1, 60, 61, 62,
+ -1, 64, -1, -1, -1, 292, 293, 294, 295, 296,
+ 297, 298, 299, 300, 35, 302, -1, 91, -1, 40,
+ 94, 42, 43, -1, 45, -1, 47, -1, 91, 123,
+ -1, 94, 126, -1, -1, -1, -1, -1, -1, 60,
+ 61, 62, -1, 64, -1, -1, -1, -1, -1, -1,
+ 292, 293, 294, 295, 296, 297, 298, 299, 300, -1,
+ 302, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 91, 35, -1, 94, -1, -1, 40, -1, 42, 43,
+ -1, 45, -1, 47, -1, 292, 293, 294, 295, 296,
+ 297, 298, 299, 300, -1, 302, 60, 61, 62, -1,
+ 64, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 292, 293, 294, 295, 296, 297, 298,
+ 299, 300, -1, 302, -1, -1, -1, 91, 40, -1,
+ 94, 43, -1, 45, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 292, 293,
+ 294, 295, 296, 297, 298, 299, 300, -1, 302, -1,
+ -1, -1, -1, 257, -1, -1, 260, 261, 262, 263,
+ 264, 265, 266, 267, -1, -1, 270, 271, 272, 273,
+ 274, 275, 276, 277, 278, 279, 280, 281, 282, 283,
+ 284, 285, 286, -1, 288, 289, 290, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 303,
+ -1, 123, -1, -1, 126, -1, -1, -1, 292, 293,
+ 294, 295, 296, 297, 298, 299, 300, -1, 302, 292,
+ 293, 294, 295, 296, 297, 298, 299, 300, -1, 302,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 292, 293, 294, 295, 296, 297, 298, 299, 300,
+ -1, 302, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 293,
+ 294, 295, 296, 297, 298, 299, 300, -1, 302, -1,
+ -1, -1, -1, -1, -1, 257, -1, -1, 260, 261,
+ 262, 263, 264, 265, 266, 267, -1, -1, 270, 271,
+ 272, 273, 274, 275, 276, 277, 278, 279, 280, 281,
+ 282, 283, 284, 285, 286, 0, 288, 289, 290, -1,
+ -1, -1, -1, -1, -1, -1, 11, -1, -1, -1,
+ -1, 303, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 30, -1, 32, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 44,
+ 45, -1, -1, 48, 49, 50, 51, -1, -1, 54,
+ -1, 56, 57, 58, 59, 60, 61, 62, -1, 64,
+ -1, -1, -1, -1, 69, 70, 71, 72, 73, 74,
+ 75, 76, -1, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, -1, -1, -1, -1, 91, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 113, 114,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 137, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 151, -1, -1, -1,
+ 155, -1, 157, -1, 159, 160, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 173,
+};
+#define YYFINAL 36
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 304
+#if YYDEBUG
+char *m2_name[] = {
+"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,"INT","HEX","ERROR","UINT","M2_TRUE",
+"M2_FALSE","CHAR","FLOAT","STRING","NAME","BLOCKNAME","IDENT","VARNAME",
+"TYPENAME","SIZE","CAP","ORD","HIGH","ABS","MIN_FUNC","MAX_FUNC","FLOAT_FUNC",
+"VAL","CHR","ODD","TRUNC","INC","DEC","INCL","EXCL","COLONCOLON","LAST",
+"REGNAME","INTERNAL_VAR","ABOVE_COMMA","ASSIGN","LEQ","GEQ","NOTEQUAL","IN",
+"OROR","LOGICAL_AND","DIV","MOD","UNARY","DOT","NOT","QID",
+};
+char *m2_rule[] = {
+"$accept : start",
+"start : exp",
+"start : type_exp",
+"type_exp : type",
+"exp : exp '^'",
+"$$1 :",
+"exp : '-' $$1 exp",
+"exp : '+' exp",
+"exp : not_exp exp",
+"not_exp : NOT",
+"not_exp : '~'",
+"exp : CAP '(' exp ')'",
+"exp : ORD '(' exp ')'",
+"exp : ABS '(' exp ')'",
+"exp : HIGH '(' exp ')'",
+"exp : MIN_FUNC '(' type ')'",
+"exp : MAX_FUNC '(' type ')'",
+"exp : FLOAT_FUNC '(' exp ')'",
+"exp : VAL '(' type ',' exp ')'",
+"exp : CHR '(' exp ')'",
+"exp : ODD '(' exp ')'",
+"exp : TRUNC '(' exp ')'",
+"exp : SIZE exp",
+"exp : INC '(' exp ')'",
+"exp : INC '(' exp ',' exp ')'",
+"exp : DEC '(' exp ')'",
+"exp : DEC '(' exp ',' exp ')'",
+"exp : exp DOT NAME",
+"exp : set",
+"exp : exp IN set",
+"exp : INCL '(' exp ',' exp ')'",
+"exp : EXCL '(' exp ',' exp ')'",
+"set : '{' arglist '}'",
+"set : type '{' arglist '}'",
+"$$2 :",
+"exp : exp '[' $$2 non_empty_arglist ']'",
+"$$3 :",
+"exp : exp '(' $$3 arglist ')'",
+"arglist :",
+"arglist : exp",
+"arglist : arglist ',' exp",
+"non_empty_arglist : exp",
+"non_empty_arglist : non_empty_arglist ',' exp",
+"exp : '{' type '}' exp",
+"exp : type '(' exp ')'",
+"exp : '(' exp ')'",
+"exp : exp '@' exp",
+"exp : exp '*' exp",
+"exp : exp '/' exp",
+"exp : exp DIV exp",
+"exp : exp MOD exp",
+"exp : exp '+' exp",
+"exp : exp '-' exp",
+"exp : exp '=' exp",
+"exp : exp NOTEQUAL exp",
+"exp : exp '#' exp",
+"exp : exp LEQ exp",
+"exp : exp GEQ exp",
+"exp : exp '<' exp",
+"exp : exp '>' exp",
+"exp : exp LOGICAL_AND exp",
+"exp : exp OROR exp",
+"exp : exp ASSIGN exp",
+"exp : M2_TRUE",
+"exp : M2_FALSE",
+"exp : INT",
+"exp : UINT",
+"exp : CHAR",
+"exp : FLOAT",
+"exp : variable",
+"exp : LAST",
+"exp : REGNAME",
+"exp : SIZE '(' type ')'",
+"exp : STRING",
+"block : fblock",
+"fblock : BLOCKNAME",
+"fblock : block COLONCOLON BLOCKNAME",
+"variable : fblock",
+"variable : INTERNAL_VAR",
+"variable : block COLONCOLON NAME",
+"variable : NAME",
+"type : TYPENAME",
+};
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 500
+#define YYMAXDEPTH 500
+#endif
+#endif
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+short yyss[YYSTACKSIZE];
+YYSTYPE yyvs[YYSTACKSIZE];
+#define yystacksize YYSTACKSIZE
+#line 658 "./m2-exp.y"
+
+#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 = xmalloc(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");
+}
+
+#line 1366 "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 3:
+#line 197 "./m2-exp.y"
+{ write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type(yyvsp[0].tval);
+ write_exp_elt_opcode(OP_TYPE);
+ }
+break;
+case 4:
+#line 206 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_IND); }
+break;
+case 5:
+#line 209 "./m2-exp.y"
+{ number_sign = -1; }
+break;
+case 6:
+#line 211 "./m2-exp.y"
+{ number_sign = 1;
+ write_exp_elt_opcode (UNOP_NEG); }
+break;
+case 7:
+#line 216 "./m2-exp.y"
+{ write_exp_elt_opcode(UNOP_PLUS); }
+break;
+case 8:
+#line 220 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+break;
+case 11:
+#line 228 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_CAP); }
+break;
+case 12:
+#line 232 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_ORD); }
+break;
+case 13:
+#line 236 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_ABS); }
+break;
+case 14:
+#line 240 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_HIGH); }
+break;
+case 15:
+#line 244 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_MIN);
+ write_exp_elt_type (yyvsp[-1].tval);
+ write_exp_elt_opcode (UNOP_MIN); }
+break;
+case 16:
+#line 250 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_MAX);
+ write_exp_elt_type (yyvsp[-1].tval);
+ write_exp_elt_opcode (UNOP_MIN); }
+break;
+case 17:
+#line 256 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_FLOAT); }
+break;
+case 18:
+#line 260 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_VAL);
+ write_exp_elt_type (yyvsp[-3].tval);
+ write_exp_elt_opcode (BINOP_VAL); }
+break;
+case 19:
+#line 266 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_CHR); }
+break;
+case 20:
+#line 270 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_ODD); }
+break;
+case 21:
+#line 274 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_TRUNC); }
+break;
+case 22:
+#line 278 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_SIZEOF); }
+break;
+case 23:
+#line 283 "./m2-exp.y"
+{ write_exp_elt_opcode(UNOP_PREINCREMENT); }
+break;
+case 24:
+#line 287 "./m2-exp.y"
+{ write_exp_elt_opcode(BINOP_ASSIGN_MODIFY);
+ write_exp_elt_opcode(BINOP_ADD);
+ write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); }
+break;
+case 25:
+#line 293 "./m2-exp.y"
+{ write_exp_elt_opcode(UNOP_PREDECREMENT);}
+break;
+case 26:
+#line 297 "./m2-exp.y"
+{ write_exp_elt_opcode(BINOP_ASSIGN_MODIFY);
+ write_exp_elt_opcode(BINOP_SUB);
+ write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); }
+break;
+case 27:
+#line 303 "./m2-exp.y"
+{ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (STRUCTOP_STRUCT); }
+break;
+case 29:
+#line 312 "./m2-exp.y"
+{ error("Sets are not implemented.");}
+break;
+case 30:
+#line 316 "./m2-exp.y"
+{ error("Sets are not implemented.");}
+break;
+case 31:
+#line 320 "./m2-exp.y"
+{ error("Sets are not implemented.");}
+break;
+case 32:
+#line 323 "./m2-exp.y"
+{ error("Sets are not implemented.");}
+break;
+case 33:
+#line 325 "./m2-exp.y"
+{ error("Sets are not implemented.");}
+break;
+case 34:
+#line 334 "./m2-exp.y"
+{ start_arglist(); }
+break;
+case 35:
+#line 336 "./m2-exp.y"
+{ write_exp_elt_opcode (MULTI_SUBSCRIPT);
+ write_exp_elt_longcst ((LONGEST) end_arglist());
+ write_exp_elt_opcode (MULTI_SUBSCRIPT); }
+break;
+case 36:
+#line 344 "./m2-exp.y"
+{ start_arglist (); }
+break;
+case 37:
+#line 346 "./m2-exp.y"
+{ write_exp_elt_opcode (OP_FUNCALL);
+ write_exp_elt_longcst ((LONGEST) end_arglist ());
+ write_exp_elt_opcode (OP_FUNCALL); }
+break;
+case 39:
+#line 355 "./m2-exp.y"
+{ arglist_len = 1; }
+break;
+case 40:
+#line 359 "./m2-exp.y"
+{ arglist_len++; }
+break;
+case 41:
+#line 364 "./m2-exp.y"
+{ arglist_len = 1; }
+break;
+case 42:
+#line 369 "./m2-exp.y"
+{ arglist_len++; }
+break;
+case 43:
+#line 374 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_MEMVAL);
+ write_exp_elt_type (yyvsp[-2].tval);
+ write_exp_elt_opcode (UNOP_MEMVAL); }
+break;
+case 44:
+#line 380 "./m2-exp.y"
+{ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (yyvsp[-3].tval);
+ write_exp_elt_opcode (UNOP_CAST); }
+break;
+case 45:
+#line 386 "./m2-exp.y"
+{ }
+break;
+case 46:
+#line 394 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_REPEAT); }
+break;
+case 47:
+#line 398 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_MUL); }
+break;
+case 48:
+#line 402 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_DIV); }
+break;
+case 49:
+#line 406 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_INTDIV); }
+break;
+case 50:
+#line 410 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_REM); }
+break;
+case 51:
+#line 414 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_ADD); }
+break;
+case 52:
+#line 418 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_SUB); }
+break;
+case 53:
+#line 422 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_EQUAL); }
+break;
+case 54:
+#line 426 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_NOTEQUAL); }
+break;
+case 55:
+#line 428 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_NOTEQUAL); }
+break;
+case 56:
+#line 432 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_LEQ); }
+break;
+case 57:
+#line 436 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_GEQ); }
+break;
+case 58:
+#line 440 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_LESS); }
+break;
+case 59:
+#line 444 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_GTR); }
+break;
+case 60:
+#line 448 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+break;
+case 61:
+#line 452 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+break;
+case 62:
+#line 456 "./m2-exp.y"
+{ write_exp_elt_opcode (BINOP_ASSIGN); }
+break;
+case 63:
+#line 463 "./m2-exp.y"
+{ write_exp_elt_opcode (OP_BOOL);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval);
+ write_exp_elt_opcode (OP_BOOL); }
+break;
+case 64:
+#line 469 "./m2-exp.y"
+{ write_exp_elt_opcode (OP_BOOL);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval);
+ write_exp_elt_opcode (OP_BOOL); }
+break;
+case 65:
+#line 475 "./m2-exp.y"
+{ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_m2_int);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+ write_exp_elt_opcode (OP_LONG); }
+break;
+case 66:
+#line 482 "./m2-exp.y"
+{
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_m2_card);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval);
+ write_exp_elt_opcode (OP_LONG);
+ }
+break;
+case 67:
+#line 491 "./m2-exp.y"
+{ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_m2_char);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval);
+ write_exp_elt_opcode (OP_LONG); }
+break;
+case 68:
+#line 499 "./m2-exp.y"
+{ write_exp_elt_opcode (OP_DOUBLE);
+ write_exp_elt_type (builtin_type_m2_real);
+ write_exp_elt_dblcst (yyvsp[0].dval);
+ write_exp_elt_opcode (OP_DOUBLE); }
+break;
+case 70:
+#line 510 "./m2-exp.y"
+{ write_exp_elt_opcode (OP_LAST);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+ write_exp_elt_opcode (OP_LAST); }
+break;
+case 71:
+#line 516 "./m2-exp.y"
+{ write_exp_elt_opcode (OP_REGISTER);
+ write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+ write_exp_elt_opcode (OP_REGISTER); }
+break;
+case 72:
+#line 522 "./m2-exp.y"
+{ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type_int);
+ write_exp_elt_longcst ((LONGEST) TYPE_LENGTH (yyvsp[-1].tval));
+ write_exp_elt_opcode (OP_LONG); }
+break;
+case 73:
+#line 529 "./m2-exp.y"
+{ write_exp_elt_opcode (OP_M2_STRING);
+ write_exp_string (yyvsp[0].sval);
+ write_exp_elt_opcode (OP_M2_STRING); }
+break;
+case 74:
+#line 536 "./m2-exp.y"
+{ yyval.bval = SYMBOL_BLOCK_VALUE(yyvsp[0].sym); }
+break;
+case 75:
+#line 540 "./m2-exp.y"
+{ struct symbol *sym
+ = lookup_symbol (copy_name (yyvsp[0].sval), expression_context_block,
+ VAR_NAMESPACE, 0, NULL);
+ yyval.sym = sym;}
+break;
+case 76:
+#line 549 "./m2-exp.y"
+{ struct symbol *tem
+ = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval,
+ VAR_NAMESPACE, 0, NULL);
+ if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
+ error ("No function \"%s\" in specified context.",
+ copy_name (yyvsp[0].sval));
+ yyval.sym = tem;
+ }
+break;
+case 77:
+#line 561 "./m2-exp.y"
+{ write_exp_elt_opcode(OP_VAR_VALUE);
+ write_exp_elt_block (NULL);
+ write_exp_elt_sym (yyvsp[0].sym);
+ write_exp_elt_opcode (OP_VAR_VALUE); }
+break;
+case 78:
+#line 569 "./m2-exp.y"
+{ write_exp_elt_opcode (OP_INTERNALVAR);
+ write_exp_elt_intern (yyvsp[0].ivar);
+ write_exp_elt_opcode (OP_INTERNALVAR); }
+break;
+case 79:
+#line 576 "./m2-exp.y"
+{ struct symbol *sym;
+ sym = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval,
+ VAR_NAMESPACE, 0, NULL);
+ if (sym == 0)
+ error ("No symbol \"%s\" in specified context.",
+ copy_name (yyvsp[0].sval));
+
+ 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); }
+break;
+case 80:
+#line 592 "./m2-exp.y"
+{ struct symbol *sym;
+ int is_a_field_of_this;
+
+ sym = lookup_symbol (copy_name (yyvsp[0].sval),
+ 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 (yyvsp[0].sval);
+
+ 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 (yyvsp[0].sval));
+ }
+ }
+break;
+case 81:
+#line 652 "./m2-exp.y"
+{ yyval.tval = lookup_typename (copy_name (yyvsp[0].sval),
+ expression_context_block, 0); }
+break;
+#line 1936 "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/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..0b678fd
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/m2-lang.c
@@ -0,0 +1,457 @@
+/* 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"
+
+/* 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;
+ 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;
+ 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)
+ 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 ("\"\"", 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,
+ TYPE_FLAG_SIGNED, "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,
+ TYPE_FLAG_SIGNED, "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,
+ TYPE_FLAG_SIGNED, "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,
+ TYPE_FLAG_SIGNED, "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,
+ TYPE_FLAG_SIGNED, "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 */
+ &builtin_type_m2_int, /* longest signed integral type */
+ &builtin_type_m2_card, /* longest unsigned integral type */
+ &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);
+
+ TYPE_NFIELDS(builtin_type_m2_bool) = 2;
+ TYPE_FIELDS(builtin_type_m2_bool) =
+ (struct field *) xmalloc (sizeof (struct field) * 2);
+ TYPE_FIELD_BITPOS(builtin_type_m2_bool,0) = 0;
+ TYPE_FIELD_NAME(builtin_type_m2_bool,0) = (char *)xmalloc(6);
+ strcpy(TYPE_FIELD_NAME(builtin_type_m2_bool,0),"FALSE");
+ TYPE_FIELD_BITPOS(builtin_type_m2_bool,1) = 1;
+ TYPE_FIELD_NAME(builtin_type_m2_bool,1) = (char *)xmalloc(5);
+ strcpy(TYPE_FIELD_NAME(builtin_type_m2_bool,1),"TRUE");
+
+ 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..4bc57f5
--- /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 *, FILE *, int, int));
+
+extern int
+m2_val_print PARAMS ((struct type *, char *, CORE_ADDR, 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..ef66a80
--- /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;
+ FILE *stream;
+ int show;
+ int level;
+{
+ extern void c_print_type PARAMS ((struct type *, char *, 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..fc17ea5
--- /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;
+ FILE *stream;
+ int format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ extern int
+ c_val_print PARAMS ((struct type *, char *, CORE_ADDR, 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..deaf624
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/main.c
@@ -0,0 +1,2799 @@
+/* Top level `main' program for GDB, the GNU debugger.
+ 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. */
+
+#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 "getopt.h"
+
+/* readline include files */
+#include "readline.h"
+#include "history.h"
+
+/* readline defines this. */
+#undef savestring
+
+#ifdef USG
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#ifndef NO_SYS_FILE
+#include <sys/file.h>
+#endif
+#include <setjmp.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#ifdef SET_STACK_LIMIT_HUGE
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int original_stack_limit;
+#endif
+
+/* Prototypes for local functions */
+
+static char *
+symbol_completion_function PARAMS ((char *, int));
+
+static void
+command_loop PARAMS ((void));
+
+static void
+command_loop_marker PARAMS ((int));
+
+static void
+print_gdb_version PARAMS ((FILE *));
+
+static void
+quit_command PARAMS ((char *, int));
+
+static void
+init_main PARAMS ((void));
+
+static void
+init_history PARAMS ((void));
+
+static void
+init_cmd_lists PARAMS ((void));
+
+static void
+float_handler PARAMS ((int));
+
+static void
+source_command PARAMS ((char *, int));
+
+static void cd_command PARAMS ((char *, int));
+
+static void
+print_gnu_advertisement PARAMS ((void));
+
+static void
+init_signals PARAMS ((void));
+
+static void
+read_command_file PARAMS ((FILE *));
+
+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
+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
+static char gdbinit[] = GDBINIT_FILENAME;
+static int inhibit_gdbinit = 0;
+
+#define ALL_CLEANUPS ((struct cleanup *)0)
+
+/* Version number of GDB, as a string. */
+
+extern char *version;
+
+/* Canonical host name as a string. */
+
+extern char *host_canonical;
+
+/* Canonical target name as a string. */
+
+extern char *target_canonical;
+
+/* 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 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). */
+static char 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 *));
+
+extern int mapped_symbol_files;
+extern int readnow_symbol_files;
+
+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;
+
+/* Baud rate specified for talking to serial target systems. Default
+ is left as -1, so targets can choose their own defaults. */
+
+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)
+#define HAVE_SIGSETMASK !defined (USG)
+#endif
+
+#if 0 == (HAVE_SIGSETMASK)
+#define sigsetmask(n)
+#endif
+
+/* Where to go for return_to_top_level (RETURN_ERROR). */
+static jmp_buf error_return;
+/* Where to go for return_to_top_level (RETURN_QUIT). */
+static jmp_buf quit_return;
+
+/* 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)
+
+/* 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);
+ (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;
+}
+
+/* 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. */
+static void
+read_command_file (stream)
+ FILE *stream;
+{
+ struct cleanup *cleanups;
+
+ cleanups = make_cleanup (source_cleanup, instream);
+ instream = stream;
+ command_loop ();
+ do_cleanups (cleanups);
+}
+
+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 (dirbuf, sizeof (dirbuf));
+ current_directory = dirbuf;
+
+#ifdef SET_STACK_LIMIT_HUGE
+ {
+ struct rlimit rlim;
+
+ /* Set the stack limit huge so that alloca (particularly stringtab
+ * in dbxread.c) does not fail. */
+ getrlimit (RLIMIT_STACK, &rlim);
+ original_stack_limit = rlim.rlim_cur;
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit (RLIMIT_STACK, &rlim);
+ }
+#endif /* SET_STACK_LIMIT_HUGE */
+
+ /* 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},
+ {"fullname", no_argument, &frame_file_full_name, 1},
+ {"f", no_argument, &frame_file_full_name, 1},
+ {"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'},
+/* 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 '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)
+ warning ("Could not set baud rate to `%s'.\n", optarg);
+ else
+ baud_rate = i;
+ }
+ break;
+
+#ifdef ADDITIONAL_OPTION_CASES
+ ADDITIONAL_OPTION_CASES
+#endif
+ case '?':
+ fprintf (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 (stderr,
+ "Excess command line arguments ignored. (%s%s)\n",
+ argv[optind], (optind == argc - 1) ? "" : " ...");
+ break;
+ }
+ if (batch)
+ quiet = 1;
+ }
+
+ /* Run the init function of each source file */
+
+ init_cmd_lists (); /* This needs to be done first */
+ initialize_all_files ();
+ init_main (); /* But that omits this file! Do it now */
+ init_signals ();
+
+ /* Do these (and anything which might call wrap_here or *_filtered)
+ after initialize_all_files. */
+ if (print_version)
+ {
+ print_gdb_version (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 (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 ("\
+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\
+", stdout);
+#ifdef ADDITIONAL_OPTION_HELP
+ fputs (ADDITIONAL_OPTION_HELP, stdout);
+#endif
+ fputs ("\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", 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 (stdout);
+ if (symarg)
+ printf_filtered ("..");
+ wrap_here("");
+ fflush (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: ";
+
+ /* 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. */
+
+ /* 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);
+ init_source_path ();
+ }
+ }
+ 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
+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. */
+static 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);
+ 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 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 (prrompt, stdout);
+ fflush (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/wi" "erd" (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;
+ extern char *rl_line_buffer;
+ extern int rl_point;
+
+ 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 ("%s", prompt);
+ fflush (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)
+ char *prrompt;
+ int repeat;
+{
+ 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 (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)
+ {
+ /* Reports are that some Sys V's don't flush stdout/err on reads
+ from stdin, when stdin/out are sockets rather than ttys. So we
+ have to do it ourselves, to make emacs-gdb and xxgdb work.
+ On other machines, doing this once per input should be a cheap nop. */
+ fflush (stdout);
+ fflush (stderr);
+
+ /* 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 (!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;
+
+ /* 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 ("%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);
+ }
+ 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 soley 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);
+ 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 ("\"info\" must be followed by the name of an info command.\n");
+ help_list (infolist, "info ", -1, stdout);
+}
+
+/* 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, 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 ("Type commands for definition of \"%s\".\n\
+End with a line saying just \"end\".\n", comname);
+ fflush (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 ("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);
+}
+
+static void
+print_gnu_advertisement()
+{
+ printf ("\
+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\
+");
+}
+
+static void
+print_gdb_version (stream)
+ FILE *stream;
+{
+ fprintf_filtered (stream, "\
+GDB %s (%s", version, host_canonical);
+
+ if (strcmp(host_canonical, target_canonical))
+ fprintf_filtered (stream, " --target %s", target_canonical);
+
+ fprintf_filtered (stream, "), ");
+ wrap_here("");
+ fprintf_filtered (stream, "Copyright 1993 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 (stdout);
+ printf_filtered ("\n");
+ immediate_quit--;
+}
+
+/* xgdb calls this to reprint the usual GDB prompt. */
+
+void
+print_prompt ()
+{
+ printf ("%s", prompt);
+ fflush (stdout);
+}
+
+static 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.");
+ }
+ }
+ /* 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 (dirbuf, sizeof (dirbuf));
+
+ if (!STREQ (dirbuf, current_directory))
+ printf ("Working directory %s\n (canonically %s).\n",
+ current_directory, dirbuf);
+ else
+ printf ("Working directory %s.\n", current_directory);
+}
+
+static 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);
+}
+
+/* ARGSUSED */
+static void
+source_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ FILE *stream;
+ struct cleanup *cleanups;
+ char *file = args;
+
+ if (file == NULL)
+ {
+ error ("source command requires pathname of file to source.");
+ }
+
+ file = tilde_expand (file);
+ make_cleanup (free, file);
+
+ stream = fopen (file, FOPEN_RT);
+ if (stream == 0)
+ perror_with_name (file);
+
+ cleanups = make_cleanup (fclose, stream);
+
+ read_command_file (stream);
+
+ do_cleanups (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 ("");
+ fflush (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 struct _hist_entry *history_get PARAMS ((int));
+ extern int history_base;
+
+ /* 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 ("\"set history\" must be followed by the name of a history subcommand.\n");
+ help_list (sethistlist, "set history ", -1, 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.");
+}
+
+/* Return whether we are running a batch file or from terminal. */
+int
+batch_mode ()
+{
+ return !(instream == stdin && ISATTY (stdin));
+}
+
+
+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.
+ */
+
+static 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
+
+ /* 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_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);
+
+ add_show_from_set (
+ add_set_cmd ("remotedebug", no_class, var_boolean, (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/maint.c b/gnu/usr.bin/gdb/gdb/maint.c
new file mode 100644
index 0000000..b533451
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/maint.c
@@ -0,0 +1,305 @@
+/* Support for GDB maintenance commands.
+ Copyright (C) 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. */
+
+
+#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"
+
+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 ("\"maintenance\" must be followed by the name of a maintenance command.\n");
+ help_list (maintenancelist, "maintenance ", -1, 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 ("\"maintenance demangle\" takes an argument to demangle.\n");
+ }
+ else
+ {
+ demangled = cplus_demangle (args, DMGL_ANSI | DMGL_PARAMS);
+ if (demangled != NULL)
+ {
+ printf ("%s\n", demangled);
+ free (demangled);
+ }
+ else
+ {
+ printf ("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 ("\"maintenance info\" must be followed by the name of an info command.\n");
+ help_list (maintenanceinfolist, "maintenance info ", -1, stdout);
+}
+
+static void
+print_section_table (abfd, asect, ignore)
+ bfd *abfd;
+ asection *asect;
+ PTR ignore;
+{
+ flagword flags;
+
+ flags = bfd_get_section_flags (abfd, asect);
+
+ 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_SHARED_LIBRARY)
+ printf_filtered (" 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 ("\"maintenance print\" must be followed by the name of a print command.\n");
+ help_list (maintenanceprintlist, "maintenance print ", -1, stdout);
+}
+
+/*
+
+GLOBAL FUNCTION
+
+ _initialize_maint_cmds -- initialize the process file system stuff
+
+SYNOPSIS
+
+ void _initialize_maint_cmds (void)
+
+DESCRIPTION
+
+ Do required initializations during gdb startup for using the
+ /proc file system interface.
+
+*/
+
+
+void
+_initialize_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);
+
+}
+
+#endif /* MAINTENANCE_CMDS */
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..74dfaa1
--- /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..dbb4e79
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/minsyms.c
@@ -0,0 +1,597 @@
+/* GDB routines for manipulating the minimal symbol tables.
+ 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 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 "symtab.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "demangle.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;
+#ifdef IBM6000_TARGET
+ struct minimal_symbol *trampoline_symbol = NULL;
+#endif
+
+ 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_unknown:
+#ifdef IBM6000_TARGET
+ /* I *think* all platforms using shared
+ libraries (and trampoline code) will suffer
+ this problem. Consider a case where there are
+ 5 shared libraries, each referencing `foo'
+ with a trampoline entry. When someone wants
+ to put a breakpoint on `foo' and the only
+ info we have is minimal symbol vector, we
+ want to use the real `foo', rather than one
+ of those trampoline entries. MGO */
+
+ /* If a trampoline symbol is found, we prefer to
+ keep looking for the *real* symbol. If the
+ actual symbol not found, then we'll use the
+ trampoline entry. Sorry for the machine
+ dependent code here, but I hope this will
+ benefit other platforms as well. For
+ trampoline entries, we used mst_unknown
+ earlier. Perhaps we should define a
+ `mst_trampoline' type?? */
+
+ if (trampoline_symbol == NULL)
+ trampoline_symbol = msymbol;
+ break;
+#else
+ /* FALLTHROUGH */
+#endif
+ 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 IBM shared library trampolines are next best. */
+#ifdef IBM6000_TARGET
+ if (trampoline_symbol)
+ return trampoline_symbol;
+#endif
+
+ 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)
+ const char *name;
+ CORE_ADDR address;
+ enum minimal_symbol_type ms_type;
+{
+ register struct msym_bunch *new;
+ register struct minimal_symbol *msymbol;
+
+ 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) = -1;
+ MSYMBOL_TYPE (msymbol) = ms_type;
+ /* FIXME: This info, if it remains, needs its own field. */
+ MSYMBOL_INFO (msymbol) = NULL; /* FIXME! */
+ msym_bunch_index++;
+ msym_count++;
+}
+
+/* FIXME: Why don't we just combine this function with the one above
+ and pass it a NULL info pointer value if info is not needed? */
+
+void
+prim_record_minimal_symbol_and_info (name, address, ms_type, info, section)
+ const char *name;
+ CORE_ADDR address;
+ enum minimal_symbol_type ms_type;
+ char *info;
+ int section;
+{
+ register struct msym_bunch *new;
+ register struct minimal_symbol *msymbol;
+
+ 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);
+ }
+ }
+}
+
diff --git a/gnu/usr.bin/gdb/gdb/mipsread.c b/gnu/usr.bin/gdb/gdb/mipsread.c
new file mode 100644
index 0000000..199092b
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/mipsread.c
@@ -0,0 +1,3653 @@
+/* Read a symbol table in MIPS' format (Third-Eye).
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993 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. */
+
+/* This module provides three functions: mipscoff_symfile_init,
+ which initializes to read a symbol file; mipscoff_new_init, which
+ discards existing cached information when all symbols are being
+ discarded; and mipscoff_symfile_read, which reads a symbol table
+ from a file.
+
+ mipscoff_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. mipscoff_psymtab_to_symtab() is called indirectly through
+ a pointer in the psymtab to do this.
+
+ 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"
+
+/* 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/internal.h"
+#include "coff/ecoff.h" /* COFF-like aspects of ecoff files */
+
+/* FIXME: coff/internal.h and aout/aout64.h both define N_ABS. We
+ want the definition from aout/aout64.h. */
+#undef N_ABS
+
+#include "libaout.h" /* Private BFD a.out information. */
+#include "aout/aout64.h"
+#include "aout/stab_gnu.h" /* STABS information */
+
+/* FIXME: libcoff.h and libaout.h both define a couple of macros. We
+ don't use them. */
+#undef exec_hdr
+#undef obj_sym_filepos
+
+#include "libcoff.h" /* Private BFD COFF information. */
+#include "libecoff.h" /* Private BFD ECOFF 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
+
+/* Information is passed among various mipsread routines for accessing
+ symbol files. A pointer to this structure is kept in the sym_private
+ field of the objfile struct. */
+
+struct ecoff_symfile_info {
+ struct mips_pending **pending_list;
+};
+#define ECOFF_SYMFILE_INFO(o) ((struct ecoff_symfile_info *)((o)->sym_private))
+#define ECOFF_PENDING_LIST(o) (ECOFF_SYMFILE_INFO(o)->pending_list)
+
+
+/* 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 mipsread 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)
+
+struct symloc
+{
+ int fdr_idx;
+ bfd *cur_bfd;
+ 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 */
+
+struct complaint bad_file_number_complaint =
+{"bad file number %d", 0, 0};
+
+struct complaint index_complaint =
+{"bad aux index at symbol %s", 0, 0};
+
+struct complaint aux_index_complaint =
+{"bad proc end in aux found from symbol %s", 0, 0};
+
+struct complaint block_index_complaint =
+{"bad aux index at block symbol %s", 0, 0};
+
+struct complaint unknown_ext_complaint =
+{"unknown external symbol %s", 0, 0};
+
+struct complaint unknown_sym_complaint =
+{"unknown local symbol %s", 0, 0};
+
+struct complaint unknown_st_complaint =
+{"with type %d", 0, 0};
+
+struct complaint block_overflow_complaint =
+{"block containing %s overfilled", 0, 0};
+
+struct complaint basic_type_complaint =
+{"cannot map MIPS basic type 0x%x for %s", 0, 0};
+
+struct complaint unknown_type_qual_complaint =
+{"unknown type qualifier 0x%x", 0, 0};
+
+struct complaint array_index_type_complaint =
+{"illegal array index type for %s, assuming int", 0, 0};
+
+struct complaint bad_tag_guess_complaint =
+{"guessed tag type of %s incorrectly", 0, 0};
+
+struct complaint block_member_complaint =
+{"declaration block contains unhandled symbol type %d", 0, 0};
+
+struct complaint stEnd_complaint =
+{"stEnd with storage class %d not handled", 0, 0};
+
+struct complaint unknown_mips_symtype_complaint =
+{"unknown symbol type 0x%x", 0, 0};
+
+struct complaint stab_unknown_complaint =
+{"unknown stabs symbol %s", 0, 0};
+
+struct complaint pdr_for_nonsymbol_complaint =
+{"PDR for %s, but no symbol", 0, 0};
+
+struct complaint pdr_static_symbol_complaint =
+{"can't handle PDR for static proc at 0x%lx", 0, 0};
+
+struct complaint bad_setjmp_pdr_complaint =
+{"fixing bad setjmp PDR from libc", 0, 0};
+
+struct complaint bad_fbitfield_complaint =
+{"can't handle TIR fBitfield for %s", 0, 0};
+
+struct complaint bad_continued_complaint =
+{"illegal TIR continued for %s", 0, 0};
+
+struct complaint bad_rfd_entry_complaint =
+{"bad rfd entry for %s: file %d, index %d", 0, 0};
+
+struct complaint unexpected_type_code_complaint =
+{"unexpected type code for %s", 0, 0};
+
+struct complaint unable_to_cross_ref_complaint =
+{"unable to cross ref btTypedef for %s", 0, 0};
+
+struct complaint illegal_forward_tq0_complaint =
+{"illegal tq0 in forward typedef for %s", 0, 0};
+
+struct complaint illegal_forward_bt_complaint =
+{"illegal bt %d in forward typedef for %s", 0, 0};
+
+struct complaint bad_linetable_guess_complaint =
+{"guessed size of linetable for %s incorrectly", 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;
+
+/* 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;
+
+/* Extra builtin types */
+
+struct type *builtin_type_complex;
+struct type *builtin_type_double_complex;
+struct type *builtin_type_fixed_dec;
+struct type *builtin_type_float_dec;
+struct type *builtin_type_string;
+
+/* Forward declarations */
+
+static void
+read_mips_symtab PARAMS ((struct objfile *, struct section_offsets *));
+
+static void
+read_the_mips_symtab PARAMS ((bfd *));
+
+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 int
+cross_ref PARAMS ((int, union aux_ext *, struct type **, enum type_code,
+ char **, int, char *));
+
+static void
+fixup_sigtramp PARAMS ((void));
+
+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));
+
+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 *));
+
+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 char *
+mips_next_symbol_text PARAMS ((void));
+
+/* Things we export to other modules */
+
+/* Address bounds for the signal trampoline in inferior, if any */
+/* FIXME: Nothing really seems to use this. Why is it here? */
+
+CORE_ADDR sigtramp_address, sigtramp_end;
+
+static void
+mipscoff_new_init (ignore)
+ struct objfile *ignore;
+{
+ sigtramp_address = 0;
+ stabsread_new_init ();
+ buildsym_new_init ();
+}
+
+static void
+mipscoff_symfile_init (objfile)
+ struct objfile *objfile;
+{
+ if (objfile->sym_private != NULL)
+ {
+ mfree (objfile->md, objfile->sym_private);
+ }
+ objfile->sym_private = (PTR)
+ xmmalloc (objfile->md, sizeof (struct ecoff_symfile_info));
+}
+
+static void
+mipscoff_symfile_read (objfile, section_offsets, mainline)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+ int mainline;
+{
+ 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. */
+
+ read_mips_symtab (objfile, 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);
+}
+
+/* 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
+mipscoff_symfile_finish (objfile)
+ struct objfile *objfile;
+{
+ if (objfile->sym_private != NULL)
+ {
+ mfree (objfile->md, objfile->sym_private);
+ }
+
+ cur_bfd = 0;
+}
+
+/* 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
+mipscoff_psymtab_to_symtab (pst)
+ struct partial_symtab *pst;
+{
+
+ if (!pst)
+ return;
+
+ if (info_verbose)
+ {
+ printf_filtered ("Reading in symbols for %s...", pst->filename);
+ fflush (stdout);
+ }
+
+ next_symbol_text_func = mips_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");
+}
+
+/* Exported procedure: Is PC in the signal trampoline code */
+
+int
+in_sigtramp (pc, ignore)
+ CORE_ADDR pc;
+ char *ignore; /* function name */
+{
+ if (sigtramp_address == 0)
+ fixup_sigtramp ();
+ return (pc >= sigtramp_address && pc < sigtramp_end);
+}
+
+/* File-level interface functions */
+
+/* Read the symtab information from file ABFD into memory. */
+
+static void
+read_the_mips_symtab (abfd)
+ bfd *abfd;
+{
+ if (ecoff_slurp_symbolic_info (abfd) == false)
+ error ("Error reading symbol table: %s", bfd_errmsg (bfd_error));
+}
+
+/* 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 = ecoff_data (cur_bfd)->fdr;
+ f = fdrs + cf;
+ /* Object files do not have the RFD table, all refs are absolute */
+ if (f->rfdBase == 0)
+ return fdrs + rf;
+ (*ecoff_backend (cur_bfd)->swap_rfd_in)
+ (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_rfd
+ + (f->rfdBase + rf) * ecoff_backend (cur_bfd)->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 ecoff_data (cur_bfd)->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. */
+
+static void
+read_mips_symtab (objfile, section_offsets)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
+{
+ cur_bfd = objfile->obfd;
+
+ read_the_mips_symtab (objfile->obfd);
+
+ 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 ("\n%s not compiled with -g, debugging support is limited.\n",
+ objfile->name);
+ printf ("You should compile with -g2 or -g3 for best debugging support.\n");
+ fflush (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. */
+ int blocktype; /* What are we parsing. */
+ 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 mips_pending
+{
+ struct mips_pending *next; /* link */
+ char *s; /* the unswapped symbol */
+ struct type *t; /* its partial type descriptor */
+};
+
+
+/* Check whether we already saw symbol SH in file FH */
+
+static struct mips_pending *
+is_pending_symbol (fh, sh)
+ FDR *fh;
+ char *sh;
+{
+ int f_idx = fh - ecoff_data (cur_bfd)->fdr;
+ register struct mips_pending *p;
+ struct mips_pending **pending_list = ECOFF_PENDING_LIST (current_objfile);
+
+ /* 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 - ecoff_data (cur_bfd)->fdr;
+ struct mips_pending *p = is_pending_symbol (fh, sh);
+
+ /* Make sure we do not make duplicates */
+ if (!p)
+ {
+ struct mips_pending **pending_list = ECOFF_PENDING_LIST (current_objfile);
+
+ p = ((struct mips_pending *)
+ obstack_alloc (&current_objfile->psymbol_obstack,
+ sizeof (struct mips_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)
+ SYMR *sh;
+ union aux_ext *ax;
+ char *ext_sh;
+ int bigend;
+{
+ const bfd_size_type external_sym_size
+ = ecoff_backend (cur_bfd)->external_sym_size;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) =
+ ecoff_backend (cur_bfd)->swap_sym_in;
+ char *name;
+ struct symbol *s;
+ struct block *b;
+ struct mips_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 = ecoff_data (cur_bfd)->ssext + sh->iss;
+ else
+ name = ecoff_data (cur_bfd)->ss + cur_fdr->issBase + sh->iss;
+
+ 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 ||
+ sh->index == 0xfffff)
+ 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);
+ }
+ 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
+ {
+ ecoff_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 *) ecoff_data (cur_bfd)->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;
+
+ 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 mips_pending *) NULL)
+ {
+ t = new_type (NULL);
+ add_pending (cur_fdr, ext_sh, t);
+ }
+ else
+ t = pend->t;
+
+ /* Alpha cc unnamed structs do not get a tag name. */
+ if (sh->iss == 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. */
+ 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 = (ecoff_data (cur_bfd)->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;
+ s = new_symbol (name);
+ SYMBOL_NAMESPACE (s) = STRUCT_NAMESPACE;
+ SYMBOL_CLASS (s) = LOC_TYPEDEF;
+ SYMBOL_VALUE (s) = 0;
+ SYMBOL_TYPE (s) = t;
+
+ /* gcc puts out an empty struct for an opaque struct definitions. */
+ if (TYPE_NFIELDS (t) == 0)
+ {
+ TYPE_FLAGS (t) |= TYPE_FLAG_STUB;
+ SYMBOL_NAMESPACE (s) = VAR_NAMESPACE;
+ }
+ 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 ();
+ 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 == 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 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 mips_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. */
+
+ 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_mips_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 */
+ &builtin_type_complex, /* btComplex */
+ &builtin_type_double_complex, /* btDComplex */
+ 0, /* btIndirect */
+ &builtin_type_fixed_dec, /* btFixedDec */
+ &builtin_type_float_dec, /* btFloatDec */
+ &builtin_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 corrupt aux indices. */
+ if (aux_index >= (ecoff_data (cur_bfd)->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. */
+ ecoff_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);
+
+ /* 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;
+
+ ecoff_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) */
+ ecoff_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,
+ ecoff_data (cur_bfd)->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));
+
+static void
+parse_procedure (pr, search_symtab, first_off)
+ PDR *pr;
+ struct symtab *search_symtab;
+ unsigned long first_off;
+{
+ 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. */
+ complain (&pdr_static_symbol_complaint, (unsigned long) pr->adr);
+ return;
+ }
+ else
+ {
+ /* external */
+ EXTR she;
+
+ (*ecoff_backend (cur_bfd)->swap_ext_in)
+ (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_ext
+ + pr->isym * ecoff_backend (cur_bfd)->external_ext_size),
+ &she);
+ sh_name = ecoff_data (cur_bfd)->ssext + she.asym.iss;
+ }
+ }
+ else
+ {
+ /* Full symbols */
+ SYMR sh;
+
+ (*ecoff_backend (cur_bfd)->swap_sym_in)
+ (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_sym
+ + ((cur_fdr->isymBase + pr->isym)
+ * ecoff_backend (cur_bfd)->external_sym_size)),
+ &sh);
+ sh_name = ecoff_data (cur_bfd)->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 += cur_fdr->adr - 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;
+ }
+
+ /* Fake PC_REGNUM for alpha __sigtramp so that read_next_frame_reg
+ will use the saved user pc from the sigcontext. */
+ if (STREQ (sh_name, "__sigtramp"))
+ e->pdr.pcreg = PC_REGNUM;
+ }
+}
+
+/* Parse the external symbol ES. Just call parse_symbol() after
+ making sure we know where the aux are for it. For procedures,
+ parsing of the PDRs has already provided all the needed
+ information, we only parse them if SKIP_PROCEDURES is false,
+ and only if this causes no symbol duplication.
+ 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 (es, skip_procedures, bigend)
+ EXTR *es;
+ int skip_procedures;
+ int bigend;
+{
+ union aux_ext *ax;
+
+ if (es->ifd != ifdNil)
+ {
+ cur_fd = es->ifd;
+ cur_fdr = ecoff_data (cur_bfd)->fdr + cur_fd;
+ ax = ecoff_data (cur_bfd)->external_aux + cur_fdr->iauxBase;
+ }
+ else
+ {
+ cur_fdr = ecoff_data (cur_bfd)->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,
+ ecoff_data (cur_bfd)->ssext + es->asym.iss,
+ fdr_name (cur_fdr));
+ return;
+ }
+
+ switch (es->asym.st)
+ {
+ case stProc:
+ /* If we have full symbols we do not need more */
+ if (skip_procedures)
+ return;
+ if (mylookup_symbol (ecoff_data (cur_bfd)->ssext + es->asym.iss,
+ top_stack->cur_block,
+ VAR_NAMESPACE, LOC_BLOCK))
+ break;
+ /* fall through */
+ 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);
+ 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 (fh, pr, lt, maxlines)
+ FDR *fh;
+ PDR *pr;
+ struct linetable *lt;
+ int maxlines;
+{
+ unsigned char *base;
+ int j, k;
+ int delta, count, lineno = 0;
+ unsigned long first_off = pr->adr;
+
+ if (fh->cbLine == 0)
+ return;
+
+ base = ecoff_data (cur_bfd)->line + fh->cbLineOffset;
+
+ /* 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 = ecoff_data (cur_bfd)->line + fh->cbLineOffset;
+ if (j != (fh->cpd - 1))
+ halt = base + pr[1].cbLineOffset;
+ else
+ halt = base + fh->cbLine;
+ base += pr->cbLineOffset;
+
+ adr = fh->adr + 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 struct ecoff_backend_data * const backend = ecoff_backend (cur_bfd);
+ const bfd_size_type external_sym_size = backend->external_sym_size;
+ const bfd_size_type external_rfd_size = backend->external_rfd_size;
+ const bfd_size_type external_ext_size = backend->external_ext_size;
+ void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
+ = backend->swap_ext_in;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
+ = backend->swap_sym_in;
+ void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *))
+ = backend->swap_rfd_in;
+ int f_idx, s_idx;
+ HDRR *hdr = &ecoff_data (cur_bfd)->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;
+
+ 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 = mips_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);
+ fdr_to_pst[-1].pst = pst;
+ FDR_IDX (pst) = -1;
+ }
+
+ /* Allocate the global pending list. */
+ ECOFF_PENDING_LIST (objfile) =
+ ((struct mips_pending **)
+ obstack_alloc (&objfile->psymbol_obstack,
+ hdr->ifdMax * sizeof (struct mips_pending *)));
+ memset ((PTR) ECOFF_PENDING_LIST (objfile), 0,
+ hdr->ifdMax * sizeof (struct mips_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 *) ecoff_data (cur_bfd)->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++)
+ 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;
+
+ 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 = ecoff_data (cur_bfd)->ssext + ext_in->asym.iss;
+ switch (ext_in->asym.st)
+ {
+ case stProc:
+ break;
+ case stStaticProc:
+ ms_type = mst_file_text;
+ break;
+ case stGlobal:
+ if (ext_in->asym.sc == scData
+ || ext_in->asym.sc == scSData
+ || ext_in->asym.sc == scRData)
+ ms_type = mst_data;
+ else
+ ms_type = mst_bss;
+ break;
+ case stLabel:
+ if (ext_in->asym.sc == scAbs)
+ ms_type = mst_abs;
+ else if (ext_in->asym.sc == scText)
+ ms_type = mst_text;
+ else if (ext_in->asym.sc == scData
+ || ext_in->asym.sc == scSData
+ || ext_in->asym.sc == scRData)
+ ms_type = mst_data;
+ else
+ ms_type = mst_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, ext_in->asym.value, ms_type);
+ }
+
+ /* 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;
+
+ cur_fdr = fh = ecoff_data (cur_bfd)->fdr + f_idx;
+
+ if (fh->csym == 0)
+ {
+ fdr_to_pst[f_idx].pst = NULL;
+ continue;
+ }
+ pst = start_psymtab_common (objfile, section_offsets,
+ fdr_name (fh),
+ fh->cpd ? fh->adr : 0,
+ 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;
+
+ /* The way to turn this into a symtab is to call... */
+ pst->read_symtab = mipscoff_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 *) ecoff_data (cur_bfd)->external_sym
+ + (fh->isymBase + 1) * external_sym_size),
+ &sh);
+ if (STREQ (ecoff_data (cur_bfd)->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 *) ecoff_data (cur_bfd)->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 = sh.value;
+ long isym;
+
+
+ isym = AUX_GET_ISYM (fh->fBigendian,
+ (ecoff_data (cur_bfd)->external_aux
+ + fh->iauxBase
+ + sh.index));
+ (*swap_sym_in) (cur_bfd,
+ (((char *)
+ ecoff_data (cur_bfd)->external_sym)
+ + ((fh->isymBase + isym - 1)
+ * external_sym_size)),
+ &sh);
+ if (sh.st == stEnd)
+ {
+ long high = procaddr + sh.value;
+ if (high > pst->texthigh)
+ pst->texthigh = high;
+ }
+ }
+ continue;
+ }
+#define SET_NAMESTRING() \
+ namestring = ecoff_data (cur_bfd)->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 *) ecoff_data (cur_bfd)->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 = ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss;
+
+ switch (sh.st)
+ {
+ long high;
+ long procaddr;
+ int new_sdx;
+
+ case stStaticProc: /* Function */
+ /* I believe this is used only for file-local functions.
+ The comment in symconst.h ("load time only static procs")
+ isn't particularly clear on this point. */
+ prim_record_minimal_symbol (name, sh.value, mst_file_text);
+ /* FALLTHROUGH */
+
+ case stProc: /* Asm labels apparently */
+ 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,
+ (ecoff_data (cur_bfd)->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 *) ecoff_data (cur_bfd)->external_sym
+ + ((fh->isymBase + cur_sdx - 1)
+ * external_sym_size)),
+ &sh);
+ if (sh.st != stEnd)
+ continue;
+ 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)
+ prim_record_minimal_symbol (name, sh.value, mst_file_data);
+ else
+ prim_record_minimal_symbol (name, sh.value, mst_file_bss);
+ class = LOC_STATIC;
+ break;
+
+ case stTypedef:/* Typedef */
+ class = LOC_TYPEDEF;
+ break;
+
+ case stConstant: /* Constant decl */
+ class = LOC_CONST;
+ break;
+
+ case stUnion:
+ case stStruct:
+ case stEnum:
+ case stBlock: /* { }, str, un, enum*/
+ if (sh.sc == scInfo || sh.sc == scCommon)
+ {
+ ADD_PSYMBOL_TO_LIST (name, strlen (name),
+ STRUCT_NAMESPACE, LOC_TYPEDEF,
+ objfile->static_psymbols,
+ sh.value,
+ psymtab_language, objfile);
+ }
+ /* 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;
+
+ 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;
+
+ switch (psh->st)
+ {
+ case stNil:
+ /* These are generated for static symbols in .o files,
+ ignore them. */
+ continue;
+ case stProc:
+ case stStaticProc:
+ class = LOC_BLOCK;
+ break;
+ case stLabel:
+ class = LOC_LABEL;
+ break;
+ default:
+ complain (&unknown_ext_complaint,
+ ecoff_data (cur_bfd)->ssext + psh->iss);
+ /* Fall through, pretend it's global. */
+ case stGlobal:
+ class = LOC_STATIC;
+ break;
+ }
+ name = ecoff_data (cur_bfd)->ssext + psh->iss;
+ ADD_PSYMBOL_ADDR_TO_LIST (name, strlen (name),
+ VAR_NAMESPACE, class,
+ objfile->global_psymbols, (CORE_ADDR) psh->value,
+ 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 + ecoff_data (cur_bfd)->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 *) ecoff_data (cur_bfd)->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;
+ }
+ }
+ do_cleanups (old_chain);
+}
+
+
+static char *
+mips_next_symbol_text ()
+{
+ SYMR sh;
+
+ cur_sdx++;
+ (*ecoff_backend (cur_bfd)->swap_sym_in)
+ (cur_bfd,
+ ((char *) ecoff_data (cur_bfd)->external_sym
+ + ((cur_fdr->isymBase + cur_sdx)
+ * ecoff_backend (cur_bfd)->external_sym_size)),
+ &sh);
+ return ecoff_data (cur_bfd)->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;
+{
+ const bfd_size_type external_sym_size
+ = ecoff_backend (cur_bfd)->external_sym_size;
+ const bfd_size_type external_pdr_size
+ = ecoff_backend (cur_bfd)->external_pdr_size;
+ void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
+ = ecoff_backend (cur_bfd)->swap_sym_in;
+ void (* const swap_pdr_in) PARAMS ((bfd *, PTR, PDR *))
+ = ecoff_backend (cur_bfd)->swap_pdr_in;
+ 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 (" ", stdout);
+ wrap_here ("");
+ fputs_filtered ("and ", stdout);
+ wrap_here ("");
+ printf_filtered ("%s...",
+ pst->dependencies[i]->filename);
+ wrap_here (""); /* Flush output */
+ fflush (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);
+ current_objfile = pst->objfile;
+ cur_fd = FDR_IDX (pst);
+ fh = (cur_fd == -1) ? (FDR *) NULL : ecoff_data (cur_bfd)->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 *) ecoff_data (cur_bfd)->external_sym
+ + (fh->isymBase + 1) * external_sym_size),
+ &sh);
+ if (STREQ (ecoff_data (cur_bfd)->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 *) ecoff_data (cur_bfd)->external_sym
+ + (fh->isymBase + cur_sdx) * external_sym_size),
+ &sh);
+ name = ecoff_data (cur_bfd)->ss + fh->issBase + sh.iss;
+ valu = sh.value;
+ if (ECOFF_IS_STAB (&sh))
+ {
+ int type_code = ECOFF_UNMARK_STAB (sh.index);
+ 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 && sh.index != indexNil)
+ {
+ /* Handle encoded stab line number. */
+ record_line (current_subfile, sh.index, valu);
+ }
+ else if (sh.st == stProc || sh.st == stStaticProc || 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);
+
+ /* This may not be necessary for stabs symtabs. FIXME. */
+ sort_blocks (st);
+
+ /* Fill in procedure info next. */
+ first_pdr = 1;
+ pdr_ptr = ((char *) ecoff_data (cur_bfd)->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);
+ }
+ }
+ 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) = fh ? fh->adr : 0;
+ 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 *) ecoff_data (cur_bfd)->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,
+ (ecoff_data (cur_bfd)->external_aux
+ + fh->iauxBase),
+ sym_ptr, fh->fBigendian);
+ 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 *) ecoff_data (cur_bfd)->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);
+ 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);
+
+ 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 = (ecoff_data (cur_bfd)->symbolic_header.isymMax
+ + ecoff_data (cur_bfd)->symbolic_header.ipdMax
+ + ecoff_data (cur_bfd)->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, 1, fh->fBigendian);
+
+ /* 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 ();
+
+ /* 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. */
+
+/* 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 mips_pending *pend;
+
+ *tpp = (struct type *)NULL;
+
+ ecoff_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 - ecoff_data (cur_bfd)->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 *) ecoff_data (cur_bfd)->external_sym
+ + ((fh->isymBase + rn->index)
+ * ecoff_backend (cur_bfd)->external_sym_size));
+ (*ecoff_backend (cur_bfd)->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 != stStruct && sh.st != stUnion
+ && sh.st != stEnum))
+ {
+ /* File indirect entry is corrupt. */
+ *pname = "<illegal>";
+ complain (&bad_rfd_entry_complaint,
+ sym_name, xref_fd, rn->index);
+ return result;
+ }
+
+ *pname = ecoff_data (cur_bfd)->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)
+ {
+ 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. 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. */
+
+ ecoff_swap_tir_in (bigend,
+ &(ecoff_data (cur_bfd)->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,
+ (ecoff_data (cur_bfd)->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,
+ ecoff_data (cur_bfd)->external_aux + fh->iauxBase,
+ sh.index,
+ (int *)NULL,
+ fh->fBigendian,
+ (ecoff_data (cur_bfd)->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;
+{
+ 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)
+ char *name;
+ struct objfile *objfile;
+{
+ struct partial_symtab *psymtab;
+
+ psymtab = allocate_psymtab (name, objfile);
+
+ /* 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;
+
+ /* The way to turn this into a symtab is to call... */
+ psymtab->read_symtab = mipscoff_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;
+}
+
+
+/* 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. */
+
+static 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 */
+ /* align_longword(sigcontext + SIGFRAME) */
+ e->pdr.frameoffset = 0x150;
+ e->pdr.framereg = SP_REGNUM;
+ /* read_next_frame_reg provides the true pc at the time of signal */
+ e->pdr.pcreg = PC_REGNUM;
+ e->pdr.regmask = -2;
+ e->pdr.regoffset = -(41 * sizeof (int));
+ e->pdr.fregmask = -1;
+ e->pdr.fregoffset = -(7 * sizeof (int));
+ 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;
+}
+
+
+/* Fake up identical offsets for all sections. */
+
+struct section_offsets *
+mipscoff_symfile_offsets (objfile, addr)
+ struct objfile *objfile;
+ CORE_ADDR addr;
+{
+ struct section_offsets *section_offsets;
+ int i;
+
+ 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;
+}
+
+/* Initialization */
+
+static struct sym_fns ecoff_sym_fns =
+{
+ "ecoff", /* sym_name: name or name prefix of BFD target type */
+ 5, /* sym_namelen: number of significant sym_name chars */
+ 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);
+
+ /* Missing basic types */
+
+ builtin_type_string =
+ init_type (TYPE_CODE_STRING,
+ TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+ 0, "string",
+ (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_fixed_dec =
+ init_type (TYPE_CODE_INT,
+ TARGET_INT_BIT / TARGET_CHAR_BIT,
+ 0, "fixed decimal",
+ (struct objfile *) NULL);
+ builtin_type_float_dec =
+ init_type (TYPE_CODE_FLT,
+ TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+ 0, "floating decimal",
+ (struct objfile *) NULL);
+}
diff --git a/gnu/usr.bin/gdb/gdb/nlmread.c b/gnu/usr.bin/gdb/gdb/nlmread.c
new file mode 100644
index 0000000..fde3af2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/nlmread.c
@@ -0,0 +1,300 @@
+/* Read NLM (NetWare Loadable Module) format executable files for GDB.
+ Copyright 1993 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 "bfd.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb-stabs.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);
+}
+
+
+/*
+
+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;
+{
+ unsigned int storage_needed;
+ asymbol *sym;
+ asymbol **symbol_table;
+ unsigned int number_of_symbols;
+ unsigned int i;
+ struct cleanup *back_to;
+ CORE_ADDR symaddr;
+ enum minimal_symbol_type ms_type;
+
+ storage_needed = get_symtab_upper_bound (abfd);
+ 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);
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ sym = symbol_table[i];
+ if (sym -> flags & BSF_GLOBAL)
+ {
+ /* 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;
+
+ 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);
+
+ /* FIXME: We could locate and read the optional native debugging format
+ here and add the symbols to the minimal symbol table. */
+
+ if (!have_partial_symbols ())
+ {
+ wrap_here ("");
+ printf_filtered ("(no debugging symbols found)...");
+ wrap_here ("");
+ }
+
+ /* 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;
+
+ 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 =
+{
+ "nlm", /* sym_name: name or name prefix of BFD target type */
+ 3, /* sym_namelen: number of significant sym_name chars */
+ 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..a7af00f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/nm.h
@@ -0,0 +1,44 @@
+/* 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 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*
+
+#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..b111f00
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/objfiles.c
@@ -0,0 +1,773 @@
+/* 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);
+ /* FIXME, we need to handle BSS segment here...it alloc's but doesn't load */
+ if (!(aflag & SEC_LOAD))
+ return;
+ if (0 == bfd_section_size (abfd, asect))
+ return;
+ section.offset = 0;
+ section.objfile = objfile;
+ section.sec_ptr = 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. */
+
+static int
+build_objfile_section_table (objfile)
+ struct objfile *objfile;
+{
+ if (objfile->sections)
+ abort();
+
+ 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;
+ int fd;
+ PTR md;
+ CORE_ADDR mapto;
+
+ 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. */
+
+ fd = open_mapped_file (bfd_get_filename (abfd), bfd_get_mtime (abfd),
+ mapped);
+ if (fd >= 0)
+ {
+ 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_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;
+{
+ int mmfd;
+
+ /* 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
+ 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. */
+ 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;
+
+ for (s = objfile->symtabs; s; s = s->next)
+ {
+ 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));
+ }
+ }
+ }
+ }
+ }
+
+ {
+ 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);
+ }
+}
+
+/* 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 (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 (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);
+}
diff --git a/gnu/usr.bin/gdb/gdb/objfiles.h b/gnu/usr.bin/gdb/gdb/objfiles.h
new file mode 100644
index 0000000..50226ff
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/objfiles.h
@@ -0,0 +1,437 @@
+/* Definitions for symbol file management in GDB.
+ 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. */
+
+#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 it's 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 (or top, depending
+ upon your stack orientation).
+
+ Gdb also supports an alternate method to avoid running off the top/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;
+
+ /* 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;
+
+};
+
+
+/* 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 sec_ptr; /* BFD section pointer */
+
+ /* Objfile this section is part of. Not currently used, but I'm sure
+ that someone will want the bfd that the sec_ptr goes with or something
+ like that before long. */
+ struct objfile *objfile;
+};
+
+/* Master structure for keeping track of each input file from which
+ gdb reads symbols. One of these is allocated for each such file we
+ access, e.g. the exec_file, symbol_file, and any shared library object
+ files. */
+
+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;
+};
+
+/* 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 it's 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 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..689f148
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/obstack.h
@@ -0,0 +1,490 @@
+/* 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 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 __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_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); \
+ (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/gdb/gdb/parse.c b/gnu/usr.bin/gdb/gdb/parse.c
new file mode 100644
index 0000000..08f2b7e
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/parse.c
@@ -0,0 +1,827 @@
+/* Parse expressions 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, 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 "symtab.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "expression.h"
+#include "value.h"
+#include "command.h"
+#include "language.h"
+#include "parser-defs.h"
+
+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);
+}
+
+/* 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, stdout, "before conversion to prefix form");
+ prefixify_expression (expout);
+ DUMP_EXPRESSION (expout, 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));
+}
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..5c8710e
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/parser-defs.h
@@ -0,0 +1,188 @@
+/* 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;
+
+struct expression *expout;
+int expout_size;
+int expout_ptr;
+
+/* If this is nonzero, this block is used as the lexical context
+ for symbol names. */
+
+struct block *expression_context_block;
+
+/* The innermost context required by the stack and register variables
+ we've encountered so far. */
+struct block *innermost_block;
+
+/* The block in which the most recently discovered symbol was found. */
+struct block *block_found;
+
+/* Number of arguments seen so far in innermost function call. */
+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;
+};
+union type_stack_elt *type_stack;
+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
+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. */
+
+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. */
+
+char *namecopy;
+
+/* Current depth in parentheses within the expression. */
+
+int paren_depth;
+
+/* Nonzero means stop parsing on first comma (if not within parentheses). */
+
+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..3be0be6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/partial-stab.h
@@ -0,0 +1,618 @@
+/* Shared code to pre-read a stab (dbx-style), when building a psymtab.
+ Copyright 1986, 1987, 1988, 1989, 1990, 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. */
+
+/* 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
+ /* 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();
+
+ 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:
+ /* Mark down an include file in the current psymtab */
+
+ SET_NAMESTRING();
+
+ /* 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;
+ }
+ }
+ 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 = 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':
+#ifdef DBXREAD_ONLY
+ /* Kludges for ELF/STABS with Sun ACC */
+ last_function_name = namestring;
+ if (pst && pst->textlow == 0)
+ 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':
+#ifdef DBXREAD_ONLY
+ /* Kludges for ELF/STABS with Sun ACC */
+ last_function_name = namestring;
+ if (pst && pst->textlow == 0)
+ 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;
+
+ default:
+ /* Unexpected symbol. Ignore it; perhaps it is an extension
+ that we don't know about.
+
+ Someone says sun cc puts out symbols like
+ /foo/baz/maclib::/usr/local/bin/maclib,
+ which would get here with a symbol type of ':'. */
+ complain (&unknown_symchar_complaint, p[1]);
+ 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 (stderr, "Had to reallocate dependency list.\n");
+ fprintf (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 ((unsigned long) 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..3530ac2
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/printcmd.c
@@ -0,0 +1,2078 @@
+/* Print values for GNU debugger GDB.
+ Copyright 1986, 1987, 1988, 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. */
+
+#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"
+
+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 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,
+ 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, 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;
+ }
+
+#ifndef CC_HAS_LONG_LONG
+ /* Make sure 'g' size is not used on integer types.
+ Well, actually, we can handle hex. */
+ if (val.size == 'g' && val.format != 'f' && val.format != 'x')
+ val.size = 'w';
+#endif
+
+ 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':
+ /* Addresses must be words. */
+ val.size = osize ? 'w' : osize;
+ 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 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 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), 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), 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, stdout, format, Val_pretty_default);
+ else
+ print_scalar_formatted (VALUE_CONTENTS (val), VALUE_TYPE (val),
+ format, size, 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;
+ 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;
+ }
+
+ 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.
+ 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;
+ FILE *stream;
+ int do_demangle;
+ char *leadin;
+{
+ CORE_ADDR name_location;
+ register struct symbol *symbol;
+ char *name;
+
+ /* First try to find the address in the symbol tables to find
+ static functions. If that doesn't succeed we try the minimal symbol
+ vector for symbols in non-text space.
+ FIXME: Should find a way to get at the static non-text symbols too. */
+
+ symbol = find_pc_function (addr);
+ if (symbol)
+ {
+ name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (symbol));
+ if (do_demangle)
+ name = SYMBOL_SOURCE_NAME (symbol);
+ else
+ name = SYMBOL_LINKAGE_NAME (symbol);
+ }
+ else
+ {
+ register struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (addr);
+
+ /* If nothing comes out, don't print anything symbolic. */
+ if (msymbol == NULL)
+ return;
+ name_location = SYMBOL_VALUE_ADDRESS (msymbol);
+ if (do_demangle)
+ name = SYMBOL_SOURCE_NAME (msymbol);
+ else
+ name = SYMBOL_LINKAGE_NAME (msymbol);
+ }
+
+ /* 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. */
+ if (symbol && 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);
+ }
+ fputs_filtered (">", stream);
+}
+
+/* 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;
+ FILE *stream;
+{
+#if 0 && defined (ADDR_BITS_REMOVE)
+ /* This is wrong for pointer to char, in which we do want to print
+ the low bits. */
+ fprintf_filtered (stream, local_hex_format(),
+ (unsigned long) ADDR_BITS_REMOVE(addr));
+#else
+ fprintf_filtered (stream, local_hex_format(), (unsigned long) addr);
+#endif
+ 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;
+ FILE *stream;
+ int do_demangle;
+{
+ if (addr == 0) {
+ fprintf_filtered (stream, "0");
+ } else if (addressprint) {
+ fprintf_filtered (stream, local_hex_format(), (unsigned long) addr);
+ 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 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, 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");
+ fflush (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 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 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 (inspect)
+ printf ("\031(gdb-makebuffer \"%s\" %d '(\"", exp, histindex);
+ else
+ if (histindex >= 0) printf_filtered ("$%d = ", histindex);
+
+ print_formatted (val, format, fmt.size);
+ printf_filtered ("\n");
+ if (inspect)
+ printf("\") )\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 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);
+
+ print_formatted (val, format, fmt.size);
+
+ 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 ("Symbol \"%s\" is a field of the local class variable `this'\n", exp);
+ return;
+ }
+
+ msymbol = lookup_minimal_symbol (exp, (struct objfile *) NULL);
+
+ if (msymbol != NULL)
+ printf ("Symbol \"%s\" is at %s in a file compiled without debugging.\n",
+ exp,
+ local_hex_string((unsigned long) SYMBOL_VALUE_ADDRESS (msymbol)));
+ else
+ error ("No symbol \"%s\" in current context.", exp);
+ return;
+ }
+
+ printf ("Symbol \"%s\" is ", SYMBOL_NAME (sym));
+ val = SYMBOL_VALUE (sym);
+ basereg = SYMBOL_BASEREG (sym);
+
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_CONST:
+ case LOC_CONST_BYTES:
+ printf ("constant");
+ break;
+
+ case LOC_LABEL:
+ printf ("a label at address %s",
+ local_hex_string((unsigned long) SYMBOL_VALUE_ADDRESS (sym)));
+ break;
+
+ case LOC_REGISTER:
+ printf ("a variable in register %s", reg_names[val]);
+ break;
+
+ case LOC_STATIC:
+ printf ("static storage at address %s",
+ local_hex_string((unsigned long) SYMBOL_VALUE_ADDRESS (sym)));
+ break;
+
+ case LOC_REGPARM:
+ printf ("an argument in register %s", reg_names[val]);
+ break;
+
+ case LOC_REGPARM_ADDR:
+ printf ("address of an argument in register %s", reg_names[val]);
+ break;
+
+ case LOC_ARG:
+ printf ("an argument at offset %ld", val);
+ break;
+
+ case LOC_LOCAL_ARG:
+ printf ("an argument at frame offset %ld", val);
+ break;
+
+ case LOC_LOCAL:
+ printf ("a local variable at frame offset %ld", val);
+ break;
+
+ case LOC_REF_ARG:
+ printf ("a reference argument at offset %ld", val);
+ break;
+
+ case LOC_BASEREG:
+ printf ("a variable at offset %ld from register %s",
+ val, reg_names[basereg]);
+ break;
+
+ case LOC_BASEREG_ARG:
+ printf ("an argument at offset %ld from register %s",
+ val, reg_names[basereg]);
+ break;
+
+ case LOC_TYPEDEF:
+ printf ("a typedef");
+ break;
+
+ case LOC_BLOCK:
+ printf ("a function at address %s",
+ local_hex_string((unsigned long) BLOCK_START (SYMBOL_BLOCK_VALUE (sym))));
+ break;
+
+ case LOC_OPTIMIZED_OUT:
+ printf_filtered ("optimized out");
+ break;
+
+ default:
+ printf ("of unknown (botched) type");
+ break;
+ }
+ printf (".\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;
+
+ printf_filtered ("%d: ", d->number);
+ if (d->format.size)
+ {
+ CORE_ADDR addr;
+
+ 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 (" ");
+ print_expression (d->exp, stdout);
+ 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);
+
+ do_examine (d->format, addr);
+ }
+ else
+ {
+ if (d->format.format)
+ printf_filtered ("/%c ", d->format.format);
+ print_expression (d->exp, stdout);
+ printf_filtered (" = ");
+ print_formatted (evaluate_expression (d->exp),
+ d->format.format, d->format.size);
+ printf_filtered ("\n");
+ }
+
+ fflush (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 ("No display number %d.\n", num);
+}
+
+void
+disable_current_display ()
+{
+ if (current_display_number >= 0)
+ {
+ disable_display (current_display_number);
+ fprintf (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 ("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, stdout);
+ if (d->block && !contained_in (get_selected_block (), d->block))
+ printf_filtered (" (cannot be evaluated in the current context)");
+ printf_filtered ("\n");
+ fflush (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 ("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;
+ FILE *stream;
+{
+ value 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;
+ FILE *stream;
+{
+ struct block *b = NULL;
+ int nsyms = 0;
+ int first = 1;
+ register int i;
+ register struct symbol *sym;
+ register value 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). There are also LOC_ARG/LOC_REGISTER pairs which
+ are not combined in symbol-reading. */
+ /* 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))
+ sym = lookup_symbol
+ (SYMBOL_NAME (sym),
+ b, VAR_NAMESPACE, (int *)NULL, (struct symtab **)NULL);
+
+ /* Print the current arg. */
+ if (! first)
+ fprintf_filtered (stream, ", ");
+ wrap_here (" ");
+ fprintf_symbol_filtered (stream, SYMBOL_SOURCE_NAME (sym),
+ SYMBOL_LANGUAGE (sym), DMGL_PARAMS | DMGL_ANSI);
+ 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));
+ if (val)
+ val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), VALUE_ADDRESS (val),
+ stream, 0, 0, 2, Val_no_prettyprint);
+ else
+ fputs_filtered ("???", stream);
+ 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;
+ 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 *val_args;
+ char *substrings;
+ char *current_substring;
+ int nargs = 0;
+ int allocated_args = 20;
+ va_list args_to_vprintf;
+ struct cleanup *old_cleanups;
+
+ val_args = (value *) xmalloc (allocated_args * sizeof (value));
+ 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 'n':
+ *f++ = '\n';
+ break;
+ case 't':
+ *f++ = '\t';
+ break;
+ case 'r':
+ *f++ = '\r';
+ break;
+ case '"':
+ *f++ = '"';
+ break;
+ default:
+ /* ??? TODO: handle other escape sequences */
+ error ("Unrecognized \\ escape character in format string.");
+ }
+ 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 vprintf 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 *) xrealloc ((char *) val_args,
+ (allocated_args *= 2)
+ * sizeof (value));
+ 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");
+
+ /* FIXME: We should be using vprintf_filtered, but as long as it
+ has an arbitrary limit that is unacceptable. Correct fix is
+ for vprintf_filtered to scan down the format string so it knows
+ how big a buffer it needs (perhaps by putting a vasprintf (see
+ GNU C library) in libiberty).
+
+ But for now, just force out any pending output, so at least the output
+ appears in the correct order. */
+ wrap_here ((char *)NULL);
+
+ /* 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;
+
+ /* Don't use printf_filtered because of arbitrary limit. */
+ printf (current_substring, str);
+ }
+ break;
+ case double_arg:
+ {
+ double val = value_as_double (val_args[i]);
+ /* Don't use printf_filtered because of arbitrary limit. */
+ printf (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]);
+ /* Don't use printf_filtered because of arbitrary limit. */
+ printf (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]);
+ /* Don't use printf_filtered because of arbitrary limit. */
+ printf (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. */
+ /* It would be OK to use printf_filtered here. */
+ printf (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 %s ", local_hex_string((unsigned long) low));
+ printf_filtered ("to %s:\n", local_hex_string((unsigned long) high));
+ }
+
+ /* Dump the specified range. */
+ for (pc = low; pc < high; )
+ {
+ QUIT;
+ print_address (pc, stdout);
+ printf_filtered (":\t");
+ pc += print_insn (pc, stdout);
+ printf_filtered ("\n");
+ }
+ printf_filtered ("End of assembler dump.\n");
+ fflush (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/putenv.c b/gnu/usr.bin/gdb/gdb/putenv.c
new file mode 100644
index 0000000..e2ea357
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/putenv.c
@@ -0,0 +1,111 @@
+/****************************************************************/
+/* */
+/* putenv(3) */
+/* */
+/* Change or add an environment entry */
+/* */
+/****************************************************************/
+/* origination 1987-Oct-7 T. Holm */
+/****************************************************************/
+
+/*
+Path: hoptoad!pacbell!ames!ll-xn!mit-eddie!uw-beaver!ssc-vax!uvicctr!tholm
+From: tholm@uvicctr.UUCP (Terrence W. Holm)
+Newsgroups: comp.os.minix
+Subject: putenv(3)
+Message-ID: <395@uvicctr.UUCP>
+Date: 5 May 88 06:40:52 GMT
+Organization: University of Victoria, Victoria B.C. Canada
+
+EFTH Minix report #2 - May 1988 - putenv(3)
+
+This is an implementation of putenv(3) that we
+wrote for Minix. Please consider this a public
+domain program.
+*/
+
+#include <stdio.h>
+
+#define PSIZE sizeof(char *)
+
+extern char **environ;
+
+char *strchr();
+char *malloc();
+
+/****************************************************************/
+/* */
+/* int */
+/* putenv( entry ) */
+/* */
+/* The "entry" should follow the form */
+/* "NAME=VALUE". This routine will search the */
+/* user environment for "NAME" and replace its */
+/* value with "VALUE". */
+/* */
+/* Note that "entry" is not copied, it is used */
+/* as the environment entry. This means that it */
+/* must not be unallocated or otherwise modifed */
+/* by the caller, unless it is replaced by a */
+/* subsequent putenv(). */
+/* */
+/* If the name is not found in the environment, */
+/* then a new vector of pointers is allocated, */
+/* "entry" is put at the end and the global */
+/* variable "environ" is updated. */
+/* */
+/* This function normally returns NULL, but -1 */
+/* is returned if it can not allocate enough */
+/* space using malloc(3), or "entry" does not */
+/* contain a '='. */
+/* */
+/****************************************************************/
+
+
+int
+putenv( entry )
+ char *entry;
+{
+ unsigned length;
+ unsigned size;
+ char *temp;
+ char **p;
+ char **new_environ;
+
+ /* Find the length of the "NAME=" */
+
+ temp = strchr(entry,'=');
+ if ( temp == 0 )
+ return( -1 );
+
+ length = (unsigned) (temp - entry + 1);
+
+
+ /* Scan through the environment looking for "NAME=" */
+
+ for ( p=environ; *p != 0 ; p++ )
+ if ( strncmp( entry, *p, length ) == 0 )
+ {
+ *p = entry;
+ return( 0 );
+ }
+
+
+ /* The name was not found, build a bigger environment */
+
+ size = p - environ;
+
+ new_environ = (char **) malloc( (size+2)*PSIZE );
+
+ if ( new_environ == (char **) NULL )
+ return( -1 );
+
+ memcpy ((char *) new_environ, (char *) environ, size*PSIZE );
+
+ new_environ[size] = entry;
+ new_environ[size+1] = NULL;
+
+ environ = new_environ;
+
+ return(0);
+}
diff --git a/gnu/usr.bin/gdb/gdb/regex.c b/gnu/usr.bin/gdb/gdb/regex.c
new file mode 100644
index 0000000..75bf4e9
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/regex.c
@@ -0,0 +1,1725 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 1985, 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. */
+
+/* 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. */
+
+#ifdef emacs
+
+/* The `emacs' switch turns on certain special matching commands
+ that make sense only in emacs. */
+
+#include "config.h"
+#include "lisp.h"
+#include "buffer.h"
+#include "syntax.h"
+
+#else /* not emacs */
+
+/* Make alloca work the best possible way. */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#ifdef sparc
+#include <alloca.h>
+#endif
+#endif
+
+/*
+ * Define the syntax stuff, so we can do the \<...\> things.
+ */
+
+#ifndef Sword /* must be non-zero in some of the tests below... */
+#define Sword 1
+#endif
+
+#define SYNTAX(c) re_syntax_table[c]
+
+#ifdef SYNTAX_TABLE
+
+char *re_syntax_table;
+
+#else
+
+static char re_syntax_table[256];
+
+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;
+
+ done = 1;
+}
+
+#endif /* SYNTAX_TABLE */
+#endif /* not emacs */
+
+#include "regex.h"
+
+/* 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 /* NFAILURES */
+
+/* width of a byte in bits */
+
+#define BYTEWIDTH 8
+
+#ifndef SIGN_EXTEND_CHAR
+#define SIGN_EXTEND_CHAR(x) (x)
+#endif
+
+static int obscure_syntax = 0;
+
+/* Specify the precise syntax of regexp for compilation.
+ This provides for compatibility for various utilities
+ which historically have different, incompatible syntaxes.
+
+ The argument SYNTAX is a bit-mask containing the two bits
+ RE_NO_BK_PARENS and RE_NO_BK_VBAR. */
+
+int
+re_set_syntax (syntax)
+ int syntax;
+{
+ int ret;
+
+ ret = obscure_syntax;
+ obscure_syntax = syntax;
+ return ret;
+}
+
+/* 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.
+*/
+
+#define PATPUSH(ch) (*b++ = (char) (ch))
+
+#define PATFETCH(c) \
+ {if (p == pend) goto end_of_pattern; \
+ c = * (unsigned char *) p++; \
+ if (translate) c = translate[c]; }
+
+#define PATFETCH_RAW(c) \
+ {if (p == pend) goto end_of_pattern; \
+ c = * (unsigned char *) p++; }
+
+#define PATUNFETCH p--
+
+#define EXTEND_BUFFER \
+ { char *old_buffer = bufp->buffer; \
+ if (bufp->allocated == (1<<16)) goto too_big; \
+ bufp->allocated *= 2; \
+ if (bufp->allocated > (1<<16)) bufp->allocated = (1<<16); \
+ if (!(bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated))) \
+ goto memory_exhausted; \
+ c = bufp->buffer - old_buffer; \
+ b += c; \
+ if (fixup_jump) \
+ fixup_jump += c; \
+ if (laststart) \
+ laststart += c; \
+ begalt += c; \
+ if (pending_exact) \
+ pending_exact += c; \
+ }
+
+static void store_jump (), insert_jump ();
+
+char *
+re_compile_pattern (pattern, size, bufp)
+ char *pattern;
+ int size;
+ struct re_pattern_buffer *bufp;
+{
+ register char *b = bufp->buffer;
+ register char *p = pattern;
+ char *pend = pattern + size;
+ register unsigned c, c1;
+ char *p1;
+ 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;
+
+ /* 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 = 28;
+ if (bufp->buffer)
+ /* EXTEND_BUFFER loses when bufp->allocated is 0 */
+ bufp->buffer = (char *) realloc (bufp->buffer, 28);
+ else
+ /* Caller did not allocate a buffer. Do it for him */
+ bufp->buffer = (char *) malloc (28);
+ if (!bufp->buffer) goto memory_exhausted;
+ begalt = b = bufp->buffer;
+ }
+
+ while (p != pend)
+ {
+ if (b - bufp->buffer > bufp->allocated - 10)
+ /* Note that EXTEND_BUFFER clobbers c */
+ EXTEND_BUFFER;
+
+ PATFETCH (c);
+
+ switch (c)
+ {
+ case '$':
+ if (obscure_syntax & RE_TIGHT_VBAR)
+ {
+ if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p != pend)
+ goto normal_char;
+ /* Make operand of last vbar end before this `$'. */
+ if (fixup_jump)
+ store_jump (fixup_jump, jump, b);
+ fixup_jump = 0;
+ PATPUSH (endline);
+ break;
+ }
+
+ /* $ means succeed if at end of line, but only in special contexts.
+ If randomly in the middle of a pattern, it is a normal character. */
+ if (p == pend || *p == '\n'
+ || (obscure_syntax & RE_CONTEXT_INDEP_OPS)
+ || (obscure_syntax & RE_NO_BK_PARENS
+ ? *p == ')'
+ : *p == '\\' && p[1] == ')')
+ || (obscure_syntax & RE_NO_BK_VBAR
+ ? *p == '|'
+ : *p == '\\' && p[1] == '|'))
+ {
+ PATPUSH (endline);
+ break;
+ }
+ goto normal_char;
+
+ case '^':
+ /* ^ means succeed if at beg of line, but only if no preceding pattern. */
+
+ if (laststart && 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;
+ PATPUSH (begline);
+ begalt = b;
+ }
+ else
+ PATPUSH (begline);
+ break;
+
+ case '+':
+ case '?':
+ if (obscure_syntax & RE_BK_PLUS_QM)
+ goto normal_char;
+ handle_plus:
+ case '*':
+ /* If there is no previous pattern, char not special. */
+ if (!laststart && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
+ goto normal_char;
+ /* If there is a sequence of repetition chars,
+ collapse it down to equivalent 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 0 matches is allowed,
+ and whether 2 or more matches is allowed. */
+ if (many_times_ok)
+ {
+ /* If more than one repetition is allowed,
+ put in a backward jump at the end. */
+ store_jump (b, maybe_finalize_jump, laststart - 3);
+ b += 3;
+ }
+ insert_jump (on_failure_jump, laststart, b + 3, b);
+ pending_exact = 0;
+ b += 3;
+ if (!zero_times_ok)
+ {
+ /* At least one repetition required: insert before the loop
+ a skip over the initial on-failure-jump instruction */
+ insert_jump (dummy_failure_jump, laststart, laststart + 6, b);
+ b += 3;
+ }
+ break;
+
+ case '.':
+ laststart = b;
+ PATPUSH (anychar);
+ break;
+
+ case '[':
+ while (b - bufp->buffer
+ > bufp->allocated - 3 - (1 << BYTEWIDTH) / BYTEWIDTH)
+ /* Note that EXTEND_BUFFER clobbers c */
+ EXTEND_BUFFER;
+
+ laststart = b;
+ if (*p == '^')
+ PATPUSH (charset_not), p++;
+ else
+ PATPUSH (charset);
+ p1 = p;
+
+ PATPUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+ /* Clear the whole map */
+ memset (b, '\0', (1 << BYTEWIDTH) / BYTEWIDTH);
+ /* Read in characters and ranges, setting map bits */
+ while (1)
+ {
+ PATFETCH (c);
+ if (c == ']' && p != p1 + 1) break;
+ if (*p == '-' && p[1] != ']')
+ {
+ PATFETCH (c1);
+ PATFETCH (c1);
+ while (c <= c1)
+ b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH), c++;
+ }
+ else
+ {
+ b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH);
+ }
+ }
+ /* Discard any 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_NO_BK_VBAR))
+ goto normal_char;
+ else
+ goto handle_bar;
+
+ 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;
+ if (regnum < RE_NREGS)
+ {
+ PATPUSH (start_memory);
+ PATPUSH (regnum);
+ }
+ *stackp++ = b - bufp->buffer;
+ *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)
+ {
+ PATPUSH (stop_memory);
+ PATPUSH (stackp[-1]);
+ }
+ stackp -= 2;
+ fixup_jump = 0;
+ if (*stackp)
+ fixup_jump = *stackp + bufp->buffer - 1;
+ laststart = *--stackp + bufp->buffer;
+ break;
+
+ case '|':
+ if (obscure_syntax & RE_NO_BK_VBAR)
+ goto normal_backsl;
+ handle_bar:
+ insert_jump (on_failure_jump, begalt, b + 6, b);
+ pending_exact = 0;
+ b += 3;
+ if (fixup_jump)
+ store_jump (fixup_jump, jump, b);
+ fixup_jump = b;
+ b += 3;
+ laststart = 0;
+ begalt = b;
+ break;
+
+#ifdef emacs
+ case '=':
+ PATPUSH (at_dot);
+ break;
+
+ case 's':
+ laststart = b;
+ PATPUSH (syntaxspec);
+ PATFETCH (c);
+ PATPUSH (syntax_spec_code[c]);
+ break;
+
+ case 'S':
+ laststart = b;
+ PATPUSH (notsyntaxspec);
+ PATFETCH (c);
+ PATPUSH (syntax_spec_code[c]);
+ break;
+#endif /* emacs */
+
+ case 'w':
+ laststart = b;
+ PATPUSH (wordchar);
+ break;
+
+ case 'W':
+ laststart = b;
+ PATPUSH (notwordchar);
+ break;
+
+ case '<':
+ PATPUSH (wordbeg);
+ break;
+
+ case '>':
+ PATPUSH (wordend);
+ break;
+
+ case 'b':
+ PATPUSH (wordbound);
+ break;
+
+ case 'B':
+ PATPUSH (notwordbound);
+ break;
+
+ case '`':
+ PATPUSH (begbuf);
+ break;
+
+ case '\'':
+ PATPUSH (endbuf);
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ c1 = c - '0';
+ if (c1 >= regnum)
+ goto normal_char;
+ for (stackt = stackp - 2; stackt > stackb; stackt -= 4)
+ if (*stackt == c1)
+ goto normal_char;
+ laststart = b;
+ PATPUSH (duplicate);
+ PATPUSH (c1);
+ break;
+
+ case '+':
+ case '?':
+ if (obscure_syntax & RE_BK_PLUS_QM)
+ goto handle_plus;
+
+ 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:
+ 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 == '?')))
+ {
+ laststart = b;
+ PATPUSH (exactn);
+ pending_exact = b;
+ PATPUSH (0);
+ }
+ PATPUSH (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 where `from' points a jump operation to jump to where `to' points.
+ `opcode' is the opcode to store. */
+
+static void
+store_jump (from, opcode, to)
+ char *from, *to;
+ char opcode;
+{
+ from[0] = opcode;
+ from[1] = (to - (from + 3)) & 0377;
+ from[2] = (to - (from + 3)) >> 8;
+}
+
+/* Open up space at char FROM, and insert there a jump to TO.
+ CURRENT_END gives te end of the storage no 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)
+ char op;
+ char *from, *to, *current_end;
+{
+ register char *pto = current_end + 3;
+ register char *pfrom = current_end;
+ while (pfrom != from)
+ *--pto = *--pfrom;
+ store_jump (from, op, to);
+}
+
+/* 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;
+ unsigned char *translate = (unsigned char *) bufp->translate;
+
+ unsigned char *stackb[NFAILURES];
+ unsigned char **stackp = stackb;
+
+ memset (fastmap, '\0', (1 << BYTEWIDTH));
+ bufp->fastmap_accurate = 1;
+ bufp->can_be_null = 0;
+
+ while (p)
+ {
+ 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 finalize_jump:
+ case maybe_finalize_jump:
+ case jump:
+ case dummy_failure_jump:
+ bufp->can_be_null = 1;
+ j = *p++ & 0377;
+ j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p += j + 1; /* The 1 compensates for missing ++ above */
+ 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)
+ continue;
+ p++;
+ j = *p++ & 0377;
+ j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p += j + 1; /* The 1 compensates for missing ++ above */
+ if (stackp != stackb && *stackp == p)
+ stackp--;
+ continue;
+
+ case on_failure_jump:
+ j = *p++ & 0377;
+ j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p++;
+ *++stackp = p + j;
+ 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)
+ return;
+ /* 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;
+#endif /* 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;
+ }
+
+ /* 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;
+ }
+}
+
+/* Like re_search_2, below, but only one string is specified. */
+
+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, 0, 0, string, size, startpos, range, regs, size);
+}
+
+/* Like re_match_2 but tries first a match starting 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, the starting positions tried are
+ STARTPOS, STARTPOS - 1, etc.
+ It is up to the caller to make sure that range is not so large
+ as to take the starting position outside of the input strings.
+
+The value returned is the position 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 = size1 + size2;
+ int val;
+
+ /* Update the fastmap now if not correct already */
+ if (fastmap && !pbufp->fastmap_accurate)
+ re_compile_fastmap (pbufp);
+
+ /* 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 && pbufp->can_be_null != 1)
+ {
+ if (range > 0)
+ {
+ 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]);
+
+ if (translate)
+ {
+ while (range > lim && !fastmap[translate[*p++]])
+ range--;
+ }
+ else
+ {
+ while (range > lim && !fastmap[*p++])
+ range--;
+ }
+ startpos += irange - range;
+ }
+ else
+ {
+ register unsigned char c;
+ if (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
+ && fastmap && pbufp->can_be_null == 0)
+ return -1;
+
+ val = re_match_2 (pbufp, string1, size1, string2, size2, startpos, regs, mstop);
+ if (0 <= val)
+ {
+ if (val == -2)
+ return -2;
+ return startpos;
+ }
+
+#ifdef C_ALLOCA
+ alloca (0);
+#endif /* C_ALLOCA */
+
+ advance:
+ if (!range) break;
+ 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, 0, 0, string, size, pos, regs, size);
+}
+#endif /* emacs */
+
+/* Maximum size of failure stack. Beyond this, overflow is an error. */
+
+int re_max_failures = 2000;
+
+static int memcmp_translate();
+/* Match the pattern described by PBUFP
+ against data which is the virtual concatenation of STRING1 and STRING2.
+ SIZE1 and SIZE2 are the sizes of the two data strings.
+ Start the match at position POS.
+ Do not consider matching past the position MSTOP.
+
+ 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, size1, string2, size2, pos, regs, mstop)
+ struct re_pattern_buffer *pbufp;
+ unsigned char *string1, *string2;
+ int size1, size2;
+ int pos;
+ struct re_registers *regs;
+ int mstop;
+{
+ register unsigned char *p = (unsigned char *) pbufp->buffer;
+ register unsigned char *pend = p + pbufp->used;
+ /* End of first string */
+ unsigned char *end1;
+ /* End of second string */
+ unsigned char *end2;
+ /* Pointer just past last char to consider matching */
+ unsigned char *end_match_1, *end_match_2;
+ register unsigned char *d, *dend;
+ register int mcnt;
+ unsigned char *translate = (unsigned char *) pbufp->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 two char *'s.
+ The first one pushed is where to resume scanning the pattern;
+ the second pushed is where to resume scanning the strings.
+ If the latter is zero, the failure point is a "dummy".
+ If a failure happens and the innermost failure point is dormant,
+ it discards that failure point and tries the next one. */
+
+ unsigned char *initial_stack[2 * NFAILURES];
+ unsigned char **stackb = initial_stack;
+ unsigned char **stackp = stackb, **stacke = &stackb[2 * NFAILURES];
+
+ /* Information on the "contents" of registers.
+ These are pointers into the input strings; they record
+ just what was matched (on this attempt) by some part of the pattern.
+ The start_memory command stores the start of a register's contents
+ and the stop_memory command stores the end.
+
+ At that point, regstart[regnum] points to the first character in the register,
+ regend[regnum] points to the first character beyond the end of the register,
+ regstart_seg1[regnum] is true iff regstart[regnum] points into string1,
+ and regend_seg1[regnum] is true iff regend[regnum] points into string1. */
+
+ unsigned char *regstart[RE_NREGS];
+ unsigned char *regend[RE_NREGS];
+ unsigned char regstart_seg1[RE_NREGS], regend_seg1[RE_NREGS];
+
+ /* Set up pointers to ends of strings.
+ Don't allow the second string to be empty unless both are empty. */
+ if (!size2)
+ {
+ 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;
+ }
+
+ /* Initialize \) text positions to -1
+ to mark ones that no \( or \) has been seen for. */
+
+ for (mcnt = 0; mcnt < sizeof (regend) / sizeof (*regend); mcnt++)
+ regend[mcnt] = (unsigned char *) -1;
+
+ /* `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 (pos <= size1)
+ d = string1 + pos, dend = end_match_1;
+ else
+ d = string2 + pos - size1, dend = end_match_2;
+
+/* Write PREFETCH; just before fetching a character with *d. */
+#define PREFETCH \
+ while (d == dend) \
+ { if (dend == end_match_2) goto fail; /* end of string2 => failure */ \
+ d = string2; /* end of string1 => advance to string2. */ \
+ dend = end_match_2; }
+
+ /* This loop 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)
+ {
+ if (p == pend)
+ /* End of pattern means we have succeeded! */
+ {
+ /* If caller wants register contents data back, convert it to indices */
+ if (regs)
+ {
+ regs->start[0] = pos;
+ if (dend == end_match_1)
+ regs->end[0] = d - string1;
+ else
+ regs->end[0] = d - string2 + size1;
+ for (mcnt = 1; mcnt < RE_NREGS; mcnt++)
+ {
+ if (regend[mcnt] == (unsigned char *) -1)
+ {
+ regs->start[mcnt] = -1;
+ regs->end[mcnt] = -1;
+ continue;
+ }
+ if (regstart_seg1[mcnt])
+ regs->start[mcnt] = regstart[mcnt] - string1;
+ else
+ regs->start[mcnt] = regstart[mcnt] - string2 + size1;
+ if (regend_seg1[mcnt])
+ regs->end[mcnt] = regend[mcnt] - string1;
+ else
+ regs->end[mcnt] = regend[mcnt] - string2 + size1;
+ }
+ }
+ if (dend == end_match_1)
+ return (d - string1 - pos);
+ else
+ return d - string2 + size1 - pos;
+ }
+
+ /* Otherwise match next pattern command */
+#ifdef SWITCH_ENUM_BUG
+ switch ((int) ((enum regexpcode) *p++))
+#else
+ switch ((enum regexpcode) *p++)
+#endif
+ {
+
+ /* \( is represented by a start_memory, \) by a stop_memory.
+ Both of those commands contain a "register number" argument.
+ The text matched within the \( and \) is recorded under that number.
+ Then, \<digit> turns into a `duplicate' command which
+ is followed by the numeric value of <digit> as the register number. */
+
+ case start_memory:
+ regstart[*p] = d;
+ regstart_seg1[*p++] = (dend == end_match_1);
+ break;
+
+ case stop_memory:
+ regend[*p] = d;
+ regend_seg1[*p++] = (dend == end_match_1);
+ break;
+
+ case duplicate:
+ {
+ int regno = *p++; /* Get which register to match against */
+ register unsigned char *d2, *dend2;
+
+ d2 = regstart[regno];
+ dend2 = ((regstart_seg1[regno] == regend_seg1[regno])
+ ? regend[regno] : end_match_1);
+ while (1)
+ {
+ /* Advance to next segment in register contents, if necessary */
+ 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;
+
+ /* Advance to next segment in data being matched, if necessary */
+ PREFETCH;
+
+ /* mcnt gets # consecutive chars to compare */
+ mcnt = dend - d;
+ if (mcnt > dend2 - d2)
+ mcnt = dend2 - d2;
+ /* Compare that many; failure if mismatch, else skip them. */
+ if (translate ? memcmp_translate (d, d2, mcnt, translate) : memcmp (d, d2, mcnt))
+ goto fail;
+ d += mcnt, d2 += mcnt;
+ }
+ }
+ break;
+
+ case anychar:
+ /* fetch a data character */
+ PREFETCH;
+ /* Match anything but a newline. */
+ if ((translate ? translate[*d++] : *d++) == '\n')
+ goto fail;
+ break;
+
+ case charset:
+ case charset_not:
+ {
+ /* Nonzero for charset_not */
+ int not = 0;
+ register int c;
+ if (*(p - 1) == (unsigned char) charset_not)
+ not = 1;
+
+ /* fetch a data character */
+ PREFETCH;
+
+ 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;
+ d++;
+ break;
+ }
+
+ case begline:
+ if (d == string1 || d[-1] == '\n')
+ break;
+ 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:
+ if (stackp == stacke)
+ {
+ unsigned char **stackx;
+ if (stacke - stackb > re_max_failures * 2)
+ return -2;
+ stackx = (unsigned char **) alloca (2 * (stacke - stackb)
+ * sizeof (char *));
+ memcpy (stackx, stackb, (stacke - stackb) * sizeof (char *));
+ stackp = stackx + (stackp - stackb);
+ stacke = stackx + 2 * (stacke - stackb);
+ stackb = stackx;
+ }
+ mcnt = *p++ & 0377;
+ mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p++;
+ *stackp++ = mcnt + p;
+ *stackp++ = d;
+ break;
+
+ /* The end of a smart repeat has an maybe_finalize_jump back.
+ Change it either to a finalize_jump or an ordinary jump. */
+
+ case maybe_finalize_jump:
+ mcnt = *p++ & 0377;
+ mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p++;
+ {
+ register unsigned char *p2 = p;
+ /* Compare what follows with the begining of the repeat.
+ If we can establish that there is nothing that they would
+ both match, we can change to finalize_jump */
+ while (p2 != pend
+ && (*p2 == (unsigned char) stop_memory
+ || *p2 == (unsigned char) start_memory))
+ p2++;
+ 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;
+ if (p[-1] != (unsigned char) finalize_jump)
+ {
+ p[-1] = (unsigned char) jump;
+ goto nofinalize;
+ }
+
+ /* The end of a stupid repeat has a finalize-jump
+ back to the start, where another failure point will be made
+ which will point after all the repetitions found so far. */
+
+ case finalize_jump:
+ stackp -= 2;
+
+ case jump:
+ nofinalize:
+ mcnt = *p++ & 0377;
+ mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p += mcnt + 1; /* The 1 compensates for missing ++ above */
+ break;
+
+ case dummy_failure_jump:
+ if (stackp == stacke)
+ {
+ unsigned char **stackx
+ = (unsigned char **) alloca (2 * (stacke - stackb)
+ * sizeof (char *));
+ memcpy (stackx, stackb, (stacke - stackb) * sizeof (char *));
+ stackp = stackx + (stackp - stackb);
+ stacke = stackx + 2 * (stacke - stackb);
+ stackb = stackx;
+ }
+ *stackp++ = 0;
+ *stackp++ = 0;
+ goto nofinalize;
+
+ case wordbound:
+ if (d == string1 /* Points to first char */
+ || d == end2 /* Points to end */
+ || (d == end1 && size2 == 0)) /* Points to end */
+ break;
+ if ((SYNTAX (d[-1]) == Sword)
+ != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
+ break;
+ goto fail;
+
+ case notwordbound:
+ if (d == string1 /* Points to first char */
+ || d == end2 /* Points to end */
+ || (d == end1 && size2 == 0)) /* Points to end */
+ goto fail;
+ if ((SYNTAX (d[-1]) == Sword)
+ != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
+ goto fail;
+ break;
+
+ case wordbeg:
+ if (d == end2 /* Points to end */
+ || (d == end1 && size2 == 0) /* Points to end */
+ || SYNTAX (* (d == end1 ? string2 : d)) != Sword) /* Next char not a letter */
+ goto fail;
+ if (d == string1 /* Points to first char */
+ || SYNTAX (d[-1]) != Sword) /* prev char not letter */
+ break;
+ goto fail;
+
+ case wordend:
+ if (d == string1 /* Points to first char */
+ || SYNTAX (d[-1]) != Sword) /* prev char not letter */
+ goto fail;
+ if (d == end2 /* Points to end */
+ || (d == end1 && size2 == 0) /* Points to end */
+ || SYNTAX (d == end1 ? *string2 : *d) != Sword) /* Next char not a letter */
+ break;
+ goto fail;
+
+#ifdef emacs
+ case before_dot:
+ if (((d - string2 <= (unsigned) size2)
+ ? d - bf_p2 : d - bf_p1)
+ <= point)
+ goto fail;
+ break;
+
+ case at_dot:
+ if (((d - string2 <= (unsigned) size2)
+ ? d - bf_p2 : d - bf_p1)
+ == point)
+ goto fail;
+ break;
+
+ case after_dot:
+ if (((d - string2 <= (unsigned) size2)
+ ? d - bf_p2 : d - bf_p1)
+ >= 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;
+ break;
+
+ case notwordchar:
+ mcnt = (int) Sword;
+ goto matchnotsyntax;
+
+ case notsyntaxspec:
+ mcnt = *p++;
+ matchnotsyntax:
+ PREFETCH;
+ if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail;
+ break;
+#else
+ case wordchar:
+ PREFETCH;
+ if (SYNTAX (*d++) == 0) goto fail;
+ break;
+
+ case notwordchar:
+ PREFETCH;
+ if (SYNTAX (*d++) != 0) goto fail;
+ break;
+#endif /* not emacs */
+
+ case begbuf:
+ if (d == string1) /* Note, d cannot equal string2 */
+ break; /* unless string1 == string2. */
+ goto fail;
+
+ case endbuf:
+ if (d == end2 || (d == end1 && size2 == 0))
+ break;
+ goto fail;
+
+ case exactn:
+ /* Match the next few pattern characters exactly.
+ mcnt is how many characters to match. */
+ mcnt = *p++;
+ if (translate)
+ {
+ do
+ {
+ PREFETCH;
+ if (translate[*d++] != *p++) goto fail;
+ }
+ while (--mcnt);
+ }
+ else
+ {
+ do
+ {
+ PREFETCH;
+ if (*d++ != *p++) goto fail;
+ }
+ while (--mcnt);
+ }
+ break;
+ }
+ continue; /* Successfully matched one pattern command; keep matching */
+
+ /* Jump here if any matching operation fails. */
+ fail:
+ if (stackp != stackb)
+ /* A restart point is known. Restart there and pop it. */
+ {
+ if (!stackp[-2])
+ { /* If innermost failure point is dormant, flush it and keep looking */
+ stackp -= 2;
+ goto fail;
+ }
+ d = *--stackp;
+ p = *--stackp;
+ if (d >= string1 && d <= end1)
+ dend = end_match_1;
+ }
+ else break; /* Matching at this starting point really fails! */
+ }
+ return -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 bsd4.2 regex library */
+
+#ifndef emacs
+
+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, 0);
+}
+
+#endif /* emacs */
+
+#ifdef test
+
+#include <stdio.h>
+
+/* Indexed by a character, gives the upper case equivalent of the character */
+
+static 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
+ };
+
+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 = atoi (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);
+ }
+}
+
+#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
+
+printchar (c)
+ char c;
+{
+ if (c < 041 || 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/gdb/gdb/regex.h b/gnu/usr.bin/gdb/gdb/regex.h
new file mode 100644
index 0000000..6348c3e
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/regex.h
@@ -0,0 +1,179 @@
+/* Definitions for data structures callers pass the regex library.
+ Copyright (C) 1985, 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 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
+
+/* These bits are used in the obscure_syntax variable to choose among
+ alternative regexp syntaxes. */
+
+/* 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 1
+
+/* 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 2
+
+/* 0 means plain + or ? serves as an operator, and \+, \? are literals.
+ 1 means \+, \? are operators and plain +, ? are literals. */
+#define RE_BK_PLUS_QM 4
+
+/* 1 means | binds tighter than ^ or $.
+ 0 means the contrary. */
+#define RE_TIGHT_VBAR 8
+
+/* 1 means treat \n as an _OR operator
+ 0 means treat it as a normal character */
+#define RE_NEWLINE_OR 16
+
+/* 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 32
+
+/* Now define combinations of bits for the standard possibilities. */
+#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
+
+/* This data structure is used to represent a compiled pattern. */
+
+struct re_pattern_buffer
+ {
+ char *buffer; /* Space holding the compiled pattern commands. */
+ int allocated; /* Size of space that buffer points to */
+ int 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 quickly 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. */
+ };
+
+/* 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.
+
+ start[i] and end[i] record the string matched by \( ... \) grouping i,
+ for i from 1 to RE_NREGS - 1.
+ start[0] and end[0] record the entire string matched. */
+
+struct re_registers
+ {
+ int start[RE_NREGS];
+ int end[RE_NREGS];
+ };
+
+/* 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 whatever for its arguments.
+ Zero-bytes may appear in the compiled regular expression. */
+
+enum regexpcode
+ {
+ unused,
+ exactn, /* followed by one byte giving n, and then by n literal bytes */
+ begline, /* fails unless at beginning of line */
+ endline, /* fails 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. */
+ anychar, /* matches any one character */
+ charset, /* matches any one char belonging to specified set.
+ First following byte is # bitmap bytes.
+ Then come bytes for a bit-map 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, /* similar but match any character that is NOT one of those specified */
+ start_memory, /* starts remembering the text that is matched
+ and stores it in a memory register.
+ followed by one byte containing the register number.
+ Register numbers must be in the range 0 through NREGS. */
+ stop_memory, /* stops remembering the text that is matched
+ and stores it in a memory register.
+ followed by one byte containing the register number.
+ Register numbers must be in the range 0 through NREGS. */
+ duplicate, /* match a duplicate of something remembered.
+ Followed by one byte containing the index of the memory register. */
+ before_dot, /* Succeeds if before dot */
+ at_dot, /* Succeeds if at dot */
+ after_dot, /* Succeeds if after dot */
+ 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, Sword or such like */
+ notsyntaxspec /* Matches any character whose syntax differs from the specified. */
+ };
+
+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 ();
+
+/* 4.2 bsd compatibility (yuck) */
+extern char *re_comp ();
+extern int re_exec ();
+
+#ifdef SYNTAX_TABLE
+extern char *re_syntax_table;
+#endif
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..f4f25e4
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/remote-utils.c
@@ -0,0 +1,645 @@
+/* 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. */
+
+/* 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.
+ * put generic load here.
+
+ */
+
+#include <ctype.h>
+
+#include "defs.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(stderr, "Unrecognized arguments: `%s'.\n", junk);
+
+ /* FIXME-now: service@host? */
+
+ error("Usage: target %s <device <speed <debug>>>\n\
+or target %s <host> <port>\n", 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);
+ sr_set_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);
+
+ sr_set_desc(SERIAL_OPEN (sr_get_device()));
+ if (!sr_get_desc())
+ perror_with_name((char *) sr_get_device());
+
+ if (SERIAL_SETBAUDRATE(sr_get_desc(), sr_get_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' at baud rate of %d\n",
+ sr_get_device(), sr_get_baud_rate());
+
+ 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 ("%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 ("%c", buf);
+ else
+ printf ("<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 ("%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;
+{
+ char *file = "nothing";
+
+ if (exec_bfd)
+ file = bfd_get_filename (exec_bfd);
+
+ if (exec_bfd)
+ {
+#ifdef __GO32__
+ printf_filtered ("\tAttached to DOS asynctsr\n");
+#else
+ printf_filtered ("\tAttached to %s at %d baud\n",
+ sr_get_device(), sr_get_baud_rate());
+#endif
+ }
+
+ printf_filtered ("\tand running program %s\n", file);
+ 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)
+ putc (*p, stdout);
+
+ putc (ch, 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);
+}
+
+void
+_initialize_sr_support ()
+{
+/* FIXME-now: if target is open when baud changes... */
+ 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);
+
+/* 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..59f4d3b
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/remote-utils.h
@@ -0,0 +1,149 @@
+/* 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;
+extern int remote_debug;
+extern int baud_rate;
+
+/* get and set debug value. */
+#define sr_get_debug() (remote_debug)
+#define sr_set_debug(newval) (remote_debug = (newval))
+
+/* get and set baud rate. */
+#define sr_get_baud_rate() (baud_rate)
+#define sr_set_baud_rate(newval) (baud_rate = (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));
+
+
+#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..266d5f3
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/remote.c
@@ -0,0 +1,1272 @@
+/* Remote target communications for serial-line targets in custom GDB protocol
+ Copyright 1988, 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. */
+
+/* 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 '#'
+
+ 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
+
+ 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 extited, and AA is
+ the exit status. This is only
+ applicable for certains sorts of
+ targets.
+ or... NAATT;DD;BB Relocate the object file.
+ AA = signal number
+ TT = text address
+ DD = data address
+ BB = bss address
+ This is used by the NLM stub,
+ which is why it only has three
+ addresses rather than one per
+ section: the NLM stub always
+ sees only three sections, even
+ though gdb may see more.
+
+ 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.
+*/
+
+#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, int 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 ((void));
+
+static int
+remote_wait PARAMS ((int pid, WAITTYPE *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 */
+
+extern int baud_rate;
+
+extern int remote_debug;
+
+/* 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 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;
+
+#define PBUFSIZ 1024
+
+/* 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. */
+#if REGISTER_BYTES > MAXBUFBYTES
+#undef PBUFSIZ
+#define PBUFSIZ (REGISTER_BYTES * 2 + 32)
+#endif
+
+/* 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;
+}
+
+/* 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. */
+ /* I'm not sure this \r is needed; we don't use it any other time we
+ send an ack. */
+ SERIAL_WRITE (remote_desc, "+\r", 2);
+ 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 (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 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");
+ return -1;
+}
+
+/* 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, siggnal;
+{
+ char buf[PBUFSIZ];
+
+ if (siggnal)
+ {
+ char *name;
+ target_terminal_ours_for_output ();
+ printf_filtered ("Can't send signals to a remote system. ");
+ name = strsigno (siggnal);
+ if (name)
+ printf_filtered (name);
+ else
+ printf_filtered ("Signal %d", siggnal);
+ printf_filtered (" not sent.\n");
+ 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 ("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;
+ WAITTYPE *status;
+{
+ unsigned char buf[PBUFSIZ];
+
+ WSETEXIT ((*status), 0);
+
+ while (1)
+ {
+ unsigned char *p;
+
+ ofunc = (void (*)()) signal (SIGINT, remote_interrupt);
+ getpkt ((char *) buf, 1);
+ signal (SIGINT, ofunc);
+
+ if (buf[0] == 'E')
+ warning ("Remote failure reply: %s", buf);
+ else if (buf[0] == 'T')
+ {
+ 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);
+ }
+ break;
+ }
+ else if (buf[0] == 'N')
+ {
+ unsigned char *p1;
+ bfd_vma text_addr, data_addr, bss_addr;
+
+ /* Relocate object file. Format is NAATT;DD;BB where AA is
+ the signal number, TT is the new text address, DD is the
+ new data address, and BB is the new bss address. This is
+ used by the NLM stub; gdb may see more sections. */
+ p = &buf[3];
+ text_addr = strtoul (p, &p1, 16);
+ if (p1 == p || *p1 != ';')
+ warning ("Malformed relocation packet: Packet '%s'", buf);
+ p = p1 + 1;
+ data_addr = strtoul (p, &p1, 16);
+ if (p1 == p || *p1 != ';')
+ warning ("Malformed relocation packet: Packet '%s'", buf);
+ p = p1 + 1;
+ bss_addr = strtoul (p, &p1, 16);
+ if (p1 == p)
+ warning ("Malformed relocation packet: Packet '%s'", buf);
+
+ if (symfile_objfile != NULL
+ && (ANOFFSET (symfile_objfile->section_offsets,
+ SECT_OFF_TEXT) != text_addr
+ || ANOFFSET (symfile_objfile->section_offsets,
+ SECT_OFF_DATA) != data_addr
+ || ANOFFSET (symfile_objfile->section_offsets,
+ SECT_OFF_BSS) != bss_addr))
+ {
+ struct section_offsets *offs;
+
+ /* 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?). */
+
+ /* FIXME: Why don't the various symfile_offsets routines
+ in the sym_fns vectors set this?
+ (no good reason -kingdon). */
+ if (symfile_objfile->num_sections == 0)
+ symfile_objfile->num_sections = SECT_OFF_MAX;
+
+ 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))));
+ ANOFFSET (offs, SECT_OFF_TEXT) = text_addr;
+ ANOFFSET (offs, SECT_OFF_DATA) = data_addr;
+ ANOFFSET (offs, SECT_OFF_BSS) = bss_addr;
+
+ objfile_relocate (symfile_objfile, offs);
+ {
+ 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->sec_ptr);
+
+ if (flags & SEC_CODE)
+ {
+ s->addr += text_addr;
+ s->endaddr += text_addr;
+ }
+ else if (flags & (SEC_DATA | SEC_LOAD))
+ {
+ s->addr += data_addr;
+ s->endaddr += data_addr;
+ }
+ else if (flags & SEC_ALLOC)
+ {
+ s->addr += bss_addr;
+ s->endaddr += bss_addr;
+ }
+ }
+ }
+ }
+ break;
+ }
+ else if (buf[0] == 'W')
+ {
+ /* The remote process exited. */
+ WSETEXIT (*status, (fromhex (buf[1]) << 4) + fromhex (buf[2]));
+ return 0;
+ }
+ else if (buf[0] == 'S')
+ break;
+ else
+ warning ("Invalid remote reply: %s", buf);
+ }
+
+ WSETSTOP ((*status), (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))));
+
+ 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 ("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 send them all, 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 the remote registers from the contents of the block REGISTERS.
+ FIXME, eventually just store one register if that's all that is needed. */
+
+/* ARGSUSED */
+static void
+remote_store_registers (regno)
+ int regno;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ 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;
+
+ if (len > PBUFSIZ / 2 - 20)
+ abort ();
+
+ sprintf (buf, "M%x,%x:", 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 ();
+
+ sprintf (buf, "m%x,%x", 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, myaddr, xfersize);
+ else
+ bytes_xferred = remote_read_bytes (memaddr, 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;
+}
+
+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 ()
+{
+ int ch;
+
+ ch = SERIAL_READCHAR (remote_desc, timeout);
+
+ if (ch < 0)
+ return ch;
+
+ 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)
+ {
+ if (remote_debug)
+ {
+ *p = '\0';
+ printf ("Sending packet: %s...", buf2); fflush(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 ();
+
+ switch (ch)
+ {
+ case '+':
+ if (remote_debug)
+ printf("Ack\n");
+ return;
+ case SERIAL_TIMEOUT:
+ break; /* Retransmit buffer */
+ case SERIAL_ERROR:
+ perror_with_name ("putpkt: couldn't read ACK");
+ case SERIAL_EOF:
+ error ("putpkt: EOF while trying to read ACK");
+ default:
+ if (remote_debug)
+ printf ("%02X %c ", ch&0xFF, ch);
+ continue;
+ }
+ break; /* Here to retransmit */
+ }
+
+ if (quit_flag)
+ {
+ quit_flag = 0;
+ interrupt_query ();
+ }
+ }
+}
+
+/* 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;
+ unsigned char csum;
+ int c = 0;
+ unsigned char c1, c2;
+ int retries = 0;
+#define MAX_RETRIES 10
+
+ while (1)
+ {
+ if (quit_flag)
+ {
+ quit_flag = 0;
+ interrupt_query ();
+ }
+
+ /* 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. */
+
+ c = readchar();
+ if (c > 0 && c != '$')
+ continue;
+
+ if (c == SERIAL_TIMEOUT)
+ {
+ if (forever)
+ continue;
+ if (++retries >= MAX_RETRIES)
+ if (remote_debug) puts_filtered ("Timed out.\n");
+ goto out;
+ }
+
+ if (c == SERIAL_EOF)
+ error ("Remote connection closed");
+ if (c == SERIAL_ERROR)
+ perror_with_name ("Remote communication error");
+
+ /* Force csum to be zero here because of possible error retry. */
+ csum = 0;
+ bp = buf;
+
+ while (1)
+ {
+ c = readchar ();
+ if (c == SERIAL_TIMEOUT)
+ {
+ if (remote_debug)
+ puts_filtered ("Timeout in mid-packet, retrying\n");
+ goto whole; /* Start a new packet, count retries */
+ }
+ if (c == '$')
+ {
+ if (remote_debug)
+ puts_filtered ("Saw new packet start in middle of old one\n");
+ goto whole; /* Start a new packet, count retries */
+ }
+ if (c == '#')
+ break;
+ if (bp >= buf+PBUFSIZ-1)
+ {
+ *bp = '\0';
+ puts_filtered ("Remote packet too long: ");
+ puts_filtered (buf);
+ puts_filtered ("\n");
+ goto whole;
+ }
+ *bp++ = c;
+ csum += c;
+ }
+ *bp = 0;
+
+ c1 = fromhex (readchar ());
+ c2 = fromhex (readchar ());
+ if ((csum & 0xff) == (c1 << 4) + c2)
+ break;
+ printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
+ (c1 << 4) + c2, csum & 0xff);
+ puts_filtered (buf);
+ puts_filtered ("\n");
+
+ /* Try the whole thing again. */
+whole:
+ if (++retries < MAX_RETRIES)
+ {
+ SERIAL_WRITE (remote_desc, "-", 1);
+ }
+ else
+ {
+ printf ("Ignoring packet error, continuing...\n");
+ break;
+ }
+ }
+
+out:
+
+ SERIAL_WRITE (remote_desc, "+", 1);
+
+ if (remote_debug)
+ fprintf (stderr,"Packet received: %s\n", buf);
+}
+
+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 */
+};
+
+void
+_initialize_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..b306e8a
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/ser-unix.c
@@ -0,0 +1,633 @@
+/* Serial interface for local (hardwired) serial ports on Un*x like systems
+ 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"
+#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;
+
+ 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;
+
+#ifdef HAVE_TERMIOS
+ /* I'm not sure whether this is necessary; the manpage makes no mention
+ of discarding input when switching to/from ICANON. */
+ if (state->termios.c_lflag & ICANON)
+ new_state.termios.c_lflag |= ICANON;
+ else
+ new_state.termios.c_lflag &= ~ICANON;
+#endif
+
+#ifdef HAVE_TERMIO
+ /* I'm not sure whether this is necessary; the manpage makes no mention
+ of discarding input when switching to/from ICANON. */
+ if (state->termio.c_lflag & ICANON)
+ new_state.termio.c_lflag |= ICANON;
+ else
+ new_state.termio.c_lflag &= ~ICANON;
+#endif
+
+#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(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 |= 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 |= 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(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;
+{
+#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;
+
+ {
+ struct hardwire_ttystate state;
+
+ if (get_tty_state(scb, &state))
+ fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
+
+#ifdef HAVE_TERMIOS
+ state.termios.c_cc[VTIME] = timeout * 10;
+#endif
+
+#ifdef HAVE_TERMIO
+ state.termio.c_cc[VTIME] = timeout * 10;
+#endif
+
+ scb->current_timeout = timeout;
+
+ if (set_tty_state (scb, &state))
+ fprintf(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++;
+
+ 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)
+ return SERIAL_TIMEOUT; /* 0 chars means timeout [may need to
+ distinguish between EOF & timeouts
+ someday] */
+ 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..6913fd6
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/serial.c
@@ -0,0 +1,261 @@
+/* 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 (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 ("\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(stderr, "This command takes no args. They have been ignored.\n");
+
+ printf("[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);
+ }
+ }
+ }
+}
+
+void
+_initialize_serial ()
+{
+ 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..7e7e530
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/serial.h
@@ -0,0 +1,153 @@
+/* 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 */
+};
+
+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 ((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. */
+#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.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..88781d7
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/source.c
@@ -0,0 +1,1398 @@
+/* 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"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "gdbcore.h"
+#include "regex.h"
+#include "symfile.h"
+#include "objfiles.h"
+
+/* 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 ()
+{
+ source_path = savestring ("$cdir:$cwd", /* strlen of it */ 10);
+ 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, ':');
+ 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 == ' ' || *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 (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] == ':'))
+ {
+ /* 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, ':');
+ if (p != 0)
+ ++p;
+ else
+ break;
+ }
+ if (p == 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, ":", name, NULL);
+ old[prefix] = c;
+ *which_path = concat (temp, "", &old[prefix], NULL);
+ prefix = strlen (temp);
+ free (temp);
+ }
+ else
+ {
+ *which_path = concat (name, (old[0]? ":" : 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 colons)
+ 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, ':');
+ 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, prot);
+ 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] == ':')
+ && (p[cdir_len] == ':' || 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;
+#ifdef LSEEK_NOT_LINEAR
+ char c;
+#endif
+
+ 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
+ /* 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
+ /* st_size might be a large type, but we only support source files whose
+ size fits in an int. FIXME. */
+ size = (int) st.st_size;
+
+#ifdef BROKEN_LARGE_ALLOCA
+ data = (char *) xmalloc (size);
+ make_cleanup (free, data);
+#else
+ data = (char *) alloca (size);
+#endif
+ 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;
+ }
+ }
+#endif
+ 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;
+ printf ("\032\032%s:%d:%d:%s:0x%lx\n", s->fullname,
+ line, s->line_charpos[line - 1],
+ mid_statement ? "middle" : "beg",
+ (unsigned long) 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)
+ error ("No source file for address %s.",
+ local_hex_string((unsigned long) sal.pc));
+ sym = find_pc_function (sal.pc);
+ if (sym)
+ {
+ printf_filtered ("%s is in ",
+ local_hex_string((unsigned long) sal.pc));
+ fputs_filtered (SYMBOL_SOURCE_NAME (sym), stdout);
+ printf_filtered (" (%s:%d).\n", sal.symtab->filename, sal.line);
+ }
+ else
+ printf_filtered ("%s is at %s:%d.\n",
+ local_hex_string((unsigned long) sal.pc),
+ 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, stdout);
+ }
+ else
+ printf_filtered (".");
+ printf_filtered ("\n");
+ }
+ else if (sal.line > 0
+ && find_line_pc_range (sal.symtab, sal.line, &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, 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, stdout);
+ wrap_here (" ");
+ printf_filtered (" and ends at ");
+ print_address (end_pc, 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 (frame_file_full_name && 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..e81c314
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/stabsread.c
@@ -0,0 +1,3770 @@
+/* Support routines for decoding "stabs" debugging information format.
+ Copyright 1986, 1987, 1988, 1989, 1990, 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. */
+
+/* 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 "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 "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;
+ 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
+
+#if 0
+/* I think this can go away, all current uses have been removed.
+ GCC emits a few crazy types which can only be distinguished by the
+ name (complex, long long on some machines), but I'd say fix GCC. */
+
+/* During some calls to read_type (and thus to read_range_type), this
+ contains the name of the type being defined. Range types are only
+ used in C as basic types. We use the name to distinguish the otherwise
+ identical basic types "int" and "long" and their unsigned versions.
+ FIXME, this should disappear with better type management. */
+
+static char *long_kludge_name;
+#endif
+
+#if 0
+struct complaint dbx_class_complaint =
+{
+ "encountered DBX-style class variable debugging information.\n\
+You seem to have compiled your program with \
+\"g++ -g0\" instead of \"g++ -g\".\n\
+Therefore GDB will not know about your class variables", 0, 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) = next_symbol_text (); \
+ } while (0)
+
+
+/* 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 *));
+ }
+ 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, ':');
+ sym = find_symbol_in_list (symbols, name, pp-name);
+ if (!sym)
+ {
+ /* 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;
+
+/* 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;
+
+ /* 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));
+
+ 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: 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? We currently have to
+ read this in host floating point format, but what type
+ represents a host format "double"?
+
+ 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, sizeof (double));
+ memcpy (dbl_valu, &d, sizeof (double));
+ /* Put it in target byte order, but it's still in host
+ floating point format. */
+ SWAP_TARGET_AND_HOST (dbl_valu, sizeof (double));
+ 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 '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). Note that
+ this is only different from the BELIEVE_PCC_PROMOTION
+ case on big-endian machines.
+
+ 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 no 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.
+ Note that this code illegally combines
+ main(argc) int argc; { register int argc = 1; }
+ but this case is considered pathological and causes a warning
+ from a decent compiler. */
+ if (local_symbols
+ && local_symbols->nsyms > 0)
+ {
+ struct symbol *prev_sym;
+ prev_sym = local_symbols->symbol[local_symbols->nsyms - 1];
+ if (SYMBOL_CLASS (prev_sym) == LOC_ARG
+ && STREQ (SYMBOL_NAME (prev_sym), SYMBOL_NAME(sym)))
+ {
+ SYMBOL_CLASS (prev_sym) = LOC_REGPARM;
+ 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':
+#if 0
+ /* See comment where long_kludge_name is declared. */
+ /* Here we save the name of the symbol for read_range_type, which
+ ends up reading in the basic types. In stabs, unfortunately there
+ is no distinction between "int" and "long" types except their
+ names. Until we work out a saner type policy (eliminating most
+ builtin types and using the names specified in the files), we
+ save away the name so that far away from here in read_range_type,
+ we can examine it to decide between "int" and "long". FIXME. */
+ long_kludge_name = SYMBOL_NAME (sym);
+#endif
+ 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)
+ {
+ 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; 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);
+ }
+
+ 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;
+ 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 !defined (REG_STRUCT_HAS_ADDR)
+#define REG_STRUCT_HAS_ADDR(gcc_p) 0
+#endif
+
+ if (SYMBOL_CLASS (sym) == LOC_REGPARM
+ && REG_STRUCT_HAS_ADDR (processing_gcc_compilation)
+ && ( (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT)
+ || (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)))
+ SYMBOL_CLASS (sym) = LOC_REGPARM_ADDR;
+
+ 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 = 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;
+
+ /* 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;
+ 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;
+
+ /* 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:
+ return error_type (pp);
+ }
+
+ to = type_name = (char *)
+ obstack_alloc (&objfile -> type_obstack,
+ (((char *) strchr (*pp, ':') - (*pp)) + 1));
+
+ /* Copy the name. */
+ from = *pp + 1;
+ while ((*to++ = *from++) != ':')
+ ;
+ *--to = '\0';
+
+ /* Set the pointer ahead of the name which we just read. */
+ *pp = from;
+ }
+
+ /* Now check to see whether the type has already been declared. */
+ /* This is necessary at least in the case where the
+ program says something like
+ struct foo bar[5];
+ The compiler puts out a cross-reference; we better find
+ set the length of the structure correctly so we can
+ set the length of the array. */
+ 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 '(':
+
+ (*pp)--;
+ 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, 0, 0, NULL, objfile);
+ else
+ {
+ struct type *xtype = *dbx_lookup_type (xtypenums);
+
+ /* This can happen if we had '-' followed by a garbage character,
+ for example. */
+ if (xtype == NULL)
+ return error_type (pp);
+
+ /* 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 */
+ type1 = read_type (pp, objfile);
+ type = make_function_type (type1, dbx_lookup_type (typenums));
+ break;
+
+ case 'k': /* Const qualifier on some type (Sun) */
+ type = read_type (pp, objfile);
+ /* FIXME! For now, we ignore const and volatile qualifiers. */
+ break;
+
+ case 'B': /* Volatile qual on some type (Sun) */
+ 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': /* 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);
+ 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, 0, 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 */
+
+/* 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)++;
+ switch (fip -> list -> visibility)
+ {
+ case VISIBILITY_PRIVATE:
+ case VISIBILITY_PROTECTED:
+ break;
+
+ case VISIBILITY_PUBLIC:
+ /* Nothing to do */
+ break;
+
+ default:
+ /* Unknown visibility specifier. */
+ complain (&stabs_general_complaint,
+ "unknown visibility specifier");
+ return;
+ break;
+ }
+ }
+ 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 0
+ /* FIXME-tiemann: Can't the compiler put out something which
+ lets us distinguish these? (or maybe just not put out anything
+ for the field). What is the story here? What does the compiler
+ really do? Also, patch gdb.texinfo for this case; I document
+ it as a possible problem there. Search for "DBX-style". */
+
+ /* This is wrong because this is identical to the symbols
+ produced for GCC 0-size arrays. For example:
+ typedef union {
+ int num;
+ char str[0];
+ } foo;
+ The code which dumped core in such circumstances should be
+ fixed not to dump core. */
+
+ /* g++ -g0 can put out bitpos & bitsize zero for a static
+ field. This does not give us any way of getting its
+ class, so we can't know its name. But we can just
+ ignore the field so we don't dump core and other nasty
+ stuff. */
+ if (fip -> list -> field.bitpos == 0 && fip -> list -> field.bitsize == 0)
+ {
+ complain (&dbx_class_complaint);
+ /* Ignore this field. */
+ fip -> list = fip -> list -> next;
+ }
+ else
+#endif /* 0 */
+ {
+ /* 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)
+
+ 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 != ';')
+ {
+ 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. */
+ if (*p == CPLUS_MARKER && 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[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:
+ /* Bad visibility format. */
+ return 0;
+ }
+
+ new -> visibility = *(*pp)++;
+ switch (new -> visibility)
+ {
+ case VISIBILITY_PRIVATE:
+ case VISIBILITY_PROTECTED:
+ case VISIBILITY_PUBLIC:
+ break;
+ default:
+ /* Bad visibility format. */
+ return 0;
+ }
+
+ {
+ 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);
+ }
+
+ /* 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_PUBLIC:
+ break;
+
+ default:
+ /* Should warn about this unknown 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>". Put code in
+ to handle this.
+
+ Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
+ for these, produce a type like float[][]. */
+
+ 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)++;
+ adjustable = 1;
+ }
+ lower = read_huge_number (pp, ';', &nbits);
+ if (nbits != 0)
+ return error_type (pp);
+
+ if (!(**pp >= '0' && **pp <= '9'))
+ {
+ (*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. */
+
+ if (TYPE_LENGTH (element_type) == 0 && !adjustable)
+ {
+ 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;
+
+#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;
+
+ /* 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 != ',')
+ {
+ int nbits;
+ 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) = sizeof (int);
+ 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;
+ }
+
+#if 0
+ /* This screws up perfectly good C programs with enums. FIXME. */
+ /* Is this Modula-2's BOOLEAN type? Flag it as such if so. */
+ if(TYPE_NFIELDS(type) == 2 &&
+ ((STREQ(TYPE_FIELD_NAME(type,0),"TRUE") &&
+ STREQ(TYPE_FIELD_NAME(type,1),"FALSE")) ||
+ (STREQ(TYPE_FIELD_NAME(type,1),"TRUE") &&
+ STREQ(TYPE_FIELD_NAME(type,0),"FALSE"))))
+ TYPE_CODE(type) = TYPE_CODE_BOOL;
+#endif
+
+ 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);
+
+#if 0
+ /* FIXME. Here we should just be able to make a type of the right
+ number of bits and signedness. FIXME. */
+
+ if (type_bits == TARGET_LONG_LONG_BIT)
+ return (lookup_fundamental_type (objfile,
+ signed_type? FT_LONG_LONG: FT_UNSIGNED_LONG_LONG));
+
+ if (type_bits == TARGET_INT_BIT)
+ {
+ /* FIXME -- the only way to distinguish `int' from `long'
+ is to look at its name! */
+ if (signed_type)
+ {
+ if (long_kludge_name && long_kludge_name[0] == 'l' /* long */)
+ return lookup_fundamental_type (objfile, FT_LONG);
+ else
+ return lookup_fundamental_type (objfile, FT_INTEGER);
+ }
+ else
+ {
+ if (long_kludge_name
+ && ((long_kludge_name[0] == 'u' /* unsigned */ &&
+ long_kludge_name[9] == 'l' /* long */)
+ || (long_kludge_name[0] == 'l' /* long unsigned */)))
+ return lookup_fundamental_type (objfile, FT_UNSIGNED_LONG);
+ else
+ return lookup_fundamental_type (objfile, FT_UNSIGNED_INTEGER);
+ }
+ }
+
+ if (type_bits == TARGET_SHORT_BIT)
+ return (lookup_fundamental_type (objfile,
+ signed_type? FT_SHORT: FT_UNSIGNED_SHORT));
+
+ if (type_bits == TARGET_CHAR_BIT)
+ return (lookup_fundamental_type (objfile,
+ signed_type? FT_CHAR: FT_UNSIGNED_CHAR));
+
+ if (type_bits == 0)
+ return lookup_fundamental_type (objfile, FT_VOID);
+
+ return error_type (pp);
+#else
+ return init_type (type_bits == 0 ? TYPE_CODE_VOID : TYPE_CODE_INT,
+ type_bits / TARGET_CHAR_BIT,
+ signed_type ? 0 : TYPE_FLAG_UNSIGNED, (char *)NULL,
+ objfile);
+#endif
+}
+
+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++;
+ }
+
+ 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, 0, 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_NAMESPACE (sym) = (enum namespace)((long) 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_NAMESPACE (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. */
+ 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:
+ {
+ 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));
+ }
+ 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);
+ }
+
+ 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;
+}
+
+/* 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..3b890d8
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/stabsread.h
@@ -0,0 +1,194 @@
+/* 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. */
+
+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));
+
+/* 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
+pastab_build_psymtabs PARAMS ((struct objfile *, struct section_offsets *,
+ int));
+
+#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..6fdd8c1
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/stack.c
@@ -0,0 +1,1379 @@
+/* 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"
+
+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, FILE *));
+
+static void
+catch_info PARAMS ((char *, int));
+
+static void
+locals_info PARAMS ((char *, int));
+
+static void
+print_frame_label_vars PARAMS ((FRAME, int, FILE *));
+
+static void
+print_frame_local_vars PARAMS ((FRAME, FILE *));
+
+static int
+print_block_frame_labels PARAMS ((struct block *, int *, FILE *));
+
+static int
+print_block_frame_locals PARAMS ((struct block *, FRAME, 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;
+
+/* Nonzero means print the full filename and linenumber
+ when a frame is printed, and do so in a format programs can parse. */
+
+int frame_file_full_name = 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, stdout);
+ return 0;
+}
+
+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;
+ char buf[MAX_REGISTER_RAW_SIZE];
+ CORE_ADDR sp;
+
+ /* 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))
+ {
+ /* Do this regardless of SOURCE because we don't have any source
+ to list for this frame. */
+ if (level >= 0)
+ printf_filtered ("#%-2d ", level);
+ printf_filtered ("<function called from gdb>\n");
+ return;
+ }
+ if (fi->signal_handler_caller)
+ {
+ /* Do this regardless of SOURCE because we don't have any source
+ to list for this frame. */
+ if (level >= 0)
+ printf_filtered ("#%-2d ", level);
+ printf_filtered ("<signal handler called>\n");
+ 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 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 == 0);
+
+ 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))))
+ {
+ /* In this case we have no way of knowing the source file
+ and line number, so don't print them. */
+ sal.symtab = 0;
+ /* 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)
+ {
+ if (level >= 0)
+ printf_filtered ("#%-2d ", level);
+ if (addressprint)
+ if (fi->pc != sal.pc || !sal.symtab)
+ printf_filtered ("%s in ", local_hex_string((unsigned long) fi->pc));
+ fprintf_symbol_filtered (stdout, funname ? funname : "??", funlang,
+ DMGL_NO_OPTS);
+ wrap_here (" ");
+ fputs_filtered (" (", 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)
+ {
+ wrap_here (" ");
+ printf_filtered (" at %s:%d", sal.symtab->filename, sal.line);
+ }
+
+#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) {
+ 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 (frame_file_full_name)
+ done = identify_source_line (sal.symtab, sal.line, mid_statement,
+ fi->pc);
+ if (!done)
+ {
+ if (addressprint && mid_statement)
+ printf_filtered ("%s\t", local_hex_string((unsigned long) fi->pc));
+ 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);
+
+ fflush (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 (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.
+ Fall through to default case; it's up to SETUP_ARBITRARY_FRAME
+ to complain if it doesn't like a single arg. */
+ }
+
+ 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;
+ 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 == 0);
+ 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 %s:\n",
+ selected_frame_level,
+ local_hex_string((unsigned long) FRAME_FP(frame)));
+ } else {
+ printf_filtered ("Stack frame at %s:\n",
+ local_hex_string((unsigned long) FRAME_FP(frame)));
+ }
+ printf_filtered (" %s = %s",
+ reg_names[PC_REGNUM],
+ local_hex_string((unsigned long) fi->pc));
+
+ wrap_here (" ");
+ if (funname)
+ {
+ printf_filtered (" in ");
+ fprintf_symbol_filtered (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 %s\n", reg_names[PC_REGNUM],
+ local_hex_string((unsigned long) FRAME_SAVED_PC (frame)));
+
+ {
+ 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 %s",
+ local_hex_string((unsigned long) FRAME_FP (calling_frame)));
+ if (fi->next && calling_frame)
+ puts_filtered (",");
+ wrap_here (" ");
+ if (fi->next)
+ printf_filtered (" caller of frame at %s",
+ local_hex_string ((unsigned long) fi->next->frame));
+ 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 %s,",
+ local_hex_string((unsigned long) arg_list));
+
+ 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, 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 %s,",
+ local_hex_string((unsigned long) arg_list));
+ }
+
+#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 %s\n",
+ local_hex_string((unsigned long) fsr.regs[SP_REGNUM]));
+ count = 0;
+ for (i = 0; i < NUM_REGS; 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 %s", reg_names[i],
+ local_hex_string((unsigned long) fsr.regs[i]));
+ count++;
+ }
+ if (count)
+ 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 ("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 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 (SYMBOL_CLASS (sym) == LOC_LOCAL
+ || SYMBOL_CLASS (sym) == LOC_REGISTER
+ || SYMBOL_CLASS (sym) == LOC_STATIC)
+ {
+ values_printed = 1;
+ fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
+ fputs_filtered (" = ", stream);
+ print_variable_value (sym, frame, stream);
+ fprintf_filtered (stream, "\n");
+ }
+ }
+ return values_printed;
+}
+
+/* Same, but print labels. */
+
+static int
+print_block_frame_labels (b, have_default, stream)
+ struct block *b;
+ int *have_default;
+ register 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, " %s",
+ local_hex_string((unsigned long) SYMBOL_VALUE_ADDRESS (sym)));
+ 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 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 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, 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, stdout);
+}
+
+static void
+print_frame_arg_vars (frame, stream)
+ register FRAME frame;
+ register 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, 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)
+ 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 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..197c0c3
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symfile.c
@@ -0,0 +1,1489 @@
+/* Generic symbol file reading for the GNU debugger, GDB.
+ Copyright 1990, 1991, 1992, 1993 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
+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);
+ }
+}
+
+void
+sort_all_symtab_syms ()
+{
+ 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)
+ {
+ sort_symtab_syms (s);
+ }
+ }
+}
+
+/* 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. */
+ /* ~0 will not be in any file, we hope. */
+ objfile -> ei.entry_point = ~0;
+ /* set the startup file to be an empty range. */
+ objfile -> ei.entry_file_lowpc = 0;
+ objfile -> ei.entry_file_highpc = 0;
+ }
+}
+
+/* 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;
+ }
+
+ (*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)))
+ 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);
+
+ /* If objfile->sf->sym_offsets doesn't set this, we don't care
+ (currently). */
+ objfile->num_sections = 0; /* krp-FIXME: why zero? */
+ 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);
+
+ /* Don't allow char * to have a typename (else would get caddr_t.) */
+ /* Ditto void *. FIXME should do this for all the builtin types. */
+
+ 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 ("");
+ fflush (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 ("");
+ fflush (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 ("");
+ fflush (stdout);
+ }
+
+ for (psymtab = objfile -> psymtabs;
+ psymtab != NULL;
+ psymtab = psymtab -> next)
+ {
+ psymtab_to_symtab (psymtab);
+ }
+ }
+
+ if (from_tty || info_verbose)
+ {
+ printf_filtered ("done.\n");
+ fflush (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. */
+
+void
+symbol_file_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ char *name = NULL;
+ 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 ("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
+ {
+ name = *argv;
+ }
+ argv++;
+ }
+
+ if (name == NULL)
+ {
+ error ("no symbol file name was specified");
+ }
+ else
+ {
+ symbol_file_add (name, from_tty, (CORE_ADDR)0, 1, mapped, readnow);
+ set_initial_language ();
+ }
+ 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_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_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;
+
+ for (sf = symtab_fns; sf != NULL; sf = sf -> next)
+ {
+ if (strncmp (bfd_get_target (objfile -> obfd),
+ sf -> sym_name, sf -> sym_namelen) == 0)
+ {
+ 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 = 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_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 0x%lx\n",
+ bfd_get_section_name (loadfile_bfd, s),
+ (unsigned long) size, (unsigned long) vma);
+
+ 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) || (*args == '\000') )
+ {
+ error ("add-symbol-file takes a file name and an address");
+ }
+ name = tilde_expand (name);
+ make_cleanup (free, name);
+
+ text_addr = parse_and_eval_address (args);
+
+ 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);
+}
+
+/* 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 */
+
+the_big_top:
+ 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) {
+ printf_filtered ("`%s' has changed; re-reading symbols.\n",
+ objfile->name);
+ /* FIXME, this should use a different command...that would only
+ affect this objfile's symbols, and would reset objfile->mtime.
+ (objfile->mtime = new_modtime;)
+ HOWEVER, that command isn't written yet -- so call symbol_file_
+ command, and restart the scan from the top, because it munges
+ the object_files list. */
+ symbol_file_command (objfile->name, 0);
+ reread_one = 1;
+ goto the_big_top; /* Start over. */
+ }
+ }
+ }
+
+ if (reread_one)
+ breakpoint_re_set ();
+}
+
+
+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,".cc") || STREQ (c,".C") || STREQ (c, ".cxx"))
+ 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_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,
+ "Load the symbols from FILE, assuming FILE has been dynamically loaded.\n\
+The second argument provides the starting address of the file's text.",
+ &cmdlist);
+ c->completer = filename_completer;
+
+ 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..70bc73d
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symfile.h
@@ -0,0 +1,228 @@
+/* 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 {
+
+ /* is the name, or name prefix, of the BFD "target type" that this
+ set of functions handles. E.g. "a.out" or "sunOs" or "coff" or "elf". */
+
+ char *sym_name;
+
+ /* counts how many bytes of sym_name should be checked against the
+ BFD target type of the file being read. If an exact match is
+ desired, specify the number of characters in sym_name plus 1 for
+ the '\0'. If a prefix match is desired, specify the number of
+ characters in sym_name. */
+
+ int sym_namelen;
+
+ /* 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 *));
+
+extern void
+sort_all_symtab_syms PARAMS ((void));
+
+/* 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 demangle.c */
+
+extern void
+set_demangling_style PARAMS ((char *));
+
+#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..411a53b
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symmisc.c
@@ -0,0 +1,857 @@
+/* Do various things to symbol tables (other than lookup), for GDB.
+ 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 "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 *, FILE *));
+
+static void
+dump_psymtab PARAMS ((struct objfile *, struct partial_symtab *, FILE *));
+
+static void
+dump_msymbols PARAMS ((struct objfile *, 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 *, FILE *));
+
+struct print_symbol_args {
+ struct symbol *symbol;
+ int depth;
+ 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 %lx, bfd at %lx, %d minsyms\n\n",
+ (unsigned long) objfile,
+ (unsigned long) objfile -> obfd,
+ objfile->minimal_symbol_count);
+
+ if (objfile -> psymtabs)
+ {
+ printf_filtered ("Psymtabs:\n");
+ for (psymtab = objfile -> psymtabs;
+ psymtab != NULL;
+ psymtab = psymtab -> next)
+ {
+ printf_filtered ("%s at %lx, ",
+ psymtab -> filename, (unsigned long) psymtab);
+ 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 %lx, ",
+ symtab -> filename, (unsigned long) symtab);
+ 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;
+ 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_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;
+ FILE *outfile;
+{
+ int i;
+
+ fprintf_filtered (outfile, "\nPartial symtab for source file %s ",
+ psymtab -> filename);
+ fprintf_filtered (outfile, "(object 0x%lx)\n\n", (unsigned long) psymtab);
+ fprintf (outfile, " Read from object file %s (0x%lx)\n",
+ objfile -> name, (unsigned long) objfile);
+
+ if (psymtab -> readin)
+ {
+ fprintf_filtered (outfile,
+ " Full symtab was read (at 0x%lx by function at 0x%lx)\n",
+ (unsigned long) psymtab -> symtab,
+ (unsigned long) psymtab -> read_symtab);
+ }
+
+ /* FIXME, we need to be able to print the relocation stuff. */
+ /* This prints some garbage for anything but stabs right now. FIXME. */
+ if (psymtab->section_offsets)
+ fprintf_filtered (outfile,
+ " Relocate symbols by 0x%lx, 0x%lx, 0x%lx, 0x%lx.\n",
+ (unsigned long) ANOFFSET (psymtab->section_offsets, 0),
+ (unsigned long) ANOFFSET (psymtab->section_offsets, 1),
+ (unsigned long) ANOFFSET (psymtab->section_offsets, 2),
+ (unsigned long) ANOFFSET (psymtab->section_offsets, 3));
+
+ fprintf_filtered (outfile, " Symbols cover text addresses 0x%lx-0x%lx\n",
+ (unsigned long) psymtab -> textlow,
+ (unsigned long) psymtab -> texthigh);
+ 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 0x%lx %s\n", i,
+ (unsigned long) psymtab -> dependencies[i],
+ 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;
+ FILE *outfile;
+{
+ register int i, j;
+ int len, blen;
+ register struct linetable *l;
+ struct blockvector *bv;
+ register struct block *b;
+ int depth;
+
+ fprintf (outfile, "\nSymtab for file %s\n", symtab->filename);
+ fprintf (outfile, "Read from object file %s (%lx)\n", objfile->name,
+ (unsigned long) objfile);
+ fprintf (outfile, "Language: %s\n", language_str (symtab -> language));
+
+ /* First print the line table. */
+ l = LINETABLE (symtab);
+ if (l) {
+ fprintf (outfile, "\nLine table:\n\n");
+ len = l->nitems;
+ for (i = 0; i < len; i++)
+ fprintf (outfile, " line %ld at %lx\n", l->item[i].line,
+ (unsigned long) l->item[i].pc);
+ }
+ /* Now print the block info. */
+ fprintf (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 (outfile, "block #%03d (object 0x%lx) ", i, (unsigned long) b);
+ fprintf (outfile, "[0x%lx..0x%lx]",
+ (unsigned long) BLOCK_START (b),
+ (unsigned long) BLOCK_END (b));
+ if (BLOCK_SUPERBLOCK (b))
+ fprintf (outfile, " (under 0x%lx)",
+ (unsigned long) BLOCK_SUPERBLOCK (b));
+ if (BLOCK_FUNCTION (b))
+ {
+ fprintf (outfile, " %s", SYMBOL_NAME (BLOCK_FUNCTION (b)));
+ if (SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b)) != NULL)
+ {
+ fprintf (outfile, " %s",
+ SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b)));
+ }
+ }
+ if (BLOCK_GCC_COMPILED(b))
+ fprintf (outfile, " gcc%d compiled", BLOCK_GCC_COMPILED(b));
+ fputc ('\n', outfile);
+ 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 (outfile, "\n");
+}
+
+void
+maintenance_print_symbols (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ FILE *outfile;
+ struct cleanup *cleanups;
+ char *symname = NULL;
+ char *filename = DEV_TTY;
+ struct objfile *objfile;
+ struct symtab *s;
+
+ dont_repeat ();
+
+ if (args == NULL)
+ {
+ error ("print-symbols 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 = 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;
+ FILE *outfile = ((struct print_symbol_args *)args)->outfile;
+
+ print_spaces (depth, outfile);
+ if (SYMBOL_NAMESPACE (symbol) == LABEL_NAMESPACE)
+ {
+ fprintf (outfile, "label %s at 0x%lx\n", SYMBOL_SOURCE_NAME (symbol),
+ (unsigned long) SYMBOL_VALUE_ADDRESS (symbol));
+ 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 (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 (outfile, ";\n");
+ }
+ else
+ {
+ if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF)
+ fprintf (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 (outfile, "; ");
+ }
+ else
+ fprintf (outfile, "%s ", SYMBOL_SOURCE_NAME (symbol));
+
+ switch (SYMBOL_CLASS (symbol))
+ {
+ case LOC_CONST:
+ fprintf (outfile, "const %ld (0x%lx),",
+ SYMBOL_VALUE (symbol),
+ (unsigned long) SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_CONST_BYTES:
+ fprintf (outfile, "const %u hex bytes:",
+ TYPE_LENGTH (SYMBOL_TYPE (symbol)));
+ {
+ unsigned i;
+ for (i = 0; i < TYPE_LENGTH (SYMBOL_TYPE (symbol)); i++)
+ fprintf (outfile, " %02x",
+ (unsigned)SYMBOL_VALUE_BYTES (symbol) [i]);
+ fprintf (outfile, ",");
+ }
+ break;
+
+ case LOC_STATIC:
+ fprintf (outfile, "static at 0x%lx,",
+ (unsigned long) SYMBOL_VALUE_ADDRESS (symbol));
+ break;
+
+ case LOC_REGISTER:
+ fprintf (outfile, "register %ld,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_ARG:
+ fprintf (outfile, "arg at 0x%lx,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_LOCAL_ARG:
+ fprintf (outfile, "arg at offset 0x%lx from fp,",
+ SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_REF_ARG:
+ fprintf (outfile, "reference arg at 0x%lx,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_REGPARM:
+ fprintf (outfile, "parameter register %ld,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_REGPARM_ADDR:
+ fprintf (outfile, "address parameter register %ld,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_LOCAL:
+ fprintf (outfile, "local at 0x%lx,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_BASEREG:
+ fprintf (outfile, "local at 0x%lx from register %d",
+ SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol));
+ break;
+
+ case LOC_BASEREG_ARG:
+ fprintf (outfile, "arg at 0x%lx from register %d,",
+ SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol));
+ break;
+
+ case LOC_TYPEDEF:
+ break;
+
+ case LOC_LABEL:
+ fprintf (outfile, "label at 0x%lx",
+ (unsigned long) SYMBOL_VALUE_ADDRESS (symbol));
+ break;
+
+ case LOC_BLOCK:
+ fprintf (outfile, "block (object 0x%lx) starting at 0x%lx,",
+ (unsigned long) SYMBOL_BLOCK_VALUE (symbol),
+ (unsigned long) BLOCK_START (SYMBOL_BLOCK_VALUE (symbol)));
+ break;
+
+ case LOC_OPTIMIZED_OUT:
+ fprintf (outfile, "optimized out");
+ break;
+
+ default:
+ fprintf (outfile, "botched symbol class %x", SYMBOL_CLASS (symbol));
+ break;
+ }
+ }
+ fprintf (outfile, "\n");
+ return 1;
+}
+
+void
+maintenance_print_psymbols (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ 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 = 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;
+ 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);
+ fprintf_filtered (outfile, "0x%lx\n", SYMBOL_VALUE (p));
+ p++;
+ }
+}
+
+void
+maintenance_print_msymbols (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ 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 = 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--;
+}
+
+
+/* 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..0d0255c
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symtab.c
@@ -0,0 +1,3035 @@
+/* Symbol table lookup for the GNU debugger, GDB.
+ 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. */
+
+#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 "regex.h"
+#include "expression.h"
+#include "language.h"
+#include "demangle.h"
+
+#include <obstack.h>
+#include <assert.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));
+
+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 ("Hint: try '%s<TAB> or '%s<ESC-?>\n", name, name);
+ printf ("(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;
+ register char *copy;
+
+ s = lookup_symtab_1 (name);
+ if (s) return s;
+
+ /* 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;
+
+ /* 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);
+ 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));
+ char *opname;
+
+ is_constructor = newname && STREQ(field_name, newname);
+ if (!is_constructor)
+ is_constructor = (physname[0]=='_' && physname[1]=='_' &&
+ (isdigit(physname[2]) || physname[2]=='Q' || physname[2]=='t'));
+ if (!is_constructor)
+ is_constructor = (strncmp(physname, "__ct", 4) == 0);
+ if (!is_destructor)
+ is_destructor = (strncmp(physname, "__dt", 4) == 0);
+
+#ifndef GCC_MANGLE_BUG
+ if (is_destructor)
+ {
+ 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))
+ {
+ 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;
+
+ 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.) */
+
+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;
+ assert (center < top);
+ 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;
+ }
+ }
+ assert (top == bottom);
+ 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. */
+ 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);
+}
+
+/* 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 (symtab, thisline, startptr, endptr)
+ struct symtab *symtab;
+ int thisline;
+ CORE_ADDR *startptr, *endptr;
+{
+ struct linetable *l;
+ int ind;
+ int exact_match; /* did we get an exact linenumber match */
+
+ if (symtab == 0)
+ return 0;
+
+ if (find_line_symtab (symtab, thisline, &l, &ind, &exact_match))
+ {
+ *startptr = l->item[ind].pc;
+ /* If we have not seen an entry for the specified line,
+ assume that means the specified line has zero bytes. */
+ if (!exact_match || ind == l->nitems-1)
+ *endptr = *startptr;
+ else
+ /* Perhaps the following entry is for the following line.
+ It's worth a try. */
+ if (ind+1 < l->nitems
+ && l->item[ind+1].line == thisline + 1)
+ *endptr = l->item[ind+1].pc;
+ else
+ *endptr = find_line_pc (symtab, thisline+1);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* 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;
+}
+
+/* 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);
+ 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 ", stdout);
+ fprintf_symbol_filtered (stdout, phys_name,
+ language_cplus, DMGL_PARAMS);
+ fputs_filtered(" - possibly inlined.)\n", 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. */
+
+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, *q1;
+ 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;
+ 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);
+
+ for (p = *argptr; *p; p++)
+ {
+ if (p[0] == ':' || p[0] == ' ' || p[0] == '\t')
+ break;
+ }
+ while (p[0] == ' ' || p[0] == '\t') p++;
+
+ if ((p[0] == ':') && !is_quoted)
+ {
+
+ /* C++ */
+ 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 whitespace). */
+ 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)
+ {
+ warning ("no mangling for \"%s\"", 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 + (q1 - q));
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = '\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)
+ {
+ /* Arg is the name of a function */
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (pc);
+ 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 = (values.sals[0].end && values.sals[0].pc != pc) ? values.sals[0].end : pc;
+ }
+ 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;
+ if (tmp[0] == '~')
+ warning ("the class `%s' does not have destructor defined",
+ SYMBOL_SOURCE_NAME(sym_class));
+ else
+ warning ("the class %s does not have any method named %s",
+ SYMBOL_SOURCE_NAME(sym_class), tmp);
+ cplusplus_hint (saved_arg);
+ return_to_top_level (RETURN_ERROR);
+ }
+ }
+ else
+ {
+ /* The quotes are important if copy is empty. */
+ warning ("can't find class, struct, or union named \"%s\"",
+ 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) */
+
+ p = *argptr;
+ if (*p == '-' || *p == '+') p++;
+ while (*p >= '0' && *p <= '9')
+ p++;
+
+ if (p != *argptr && (*p == 0 || *p == ' ' || *p == '\t' || *p == ','))
+ {
+ /* 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 (p == *argptr)
+ val.line = 5;
+ if (s == 0)
+ val.line = default_line + val.line;
+ break;
+ case minus:
+ if (p == *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 (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+ 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). */
+
+ p = skip_quoted (*argptr);
+ if (is_quoted && p[-1] != '\'')
+ error ("Unmatched single quote.");
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = '\0';
+ if ((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 */
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (pc);
+ val = find_pc_line (pc, 0);
+#ifdef PROLOGUE_FIRSTLINE_OVERLAP
+ /* Convex: no need to suppress code on first line, if any */
+ val.pc = pc;
+#else
+ /* Check if SKIP_PROLOGUE left us in mid-line, and the next
+ line is still part of the same function. */
+ if (val.pc != pc
+ && BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) <= val.end
+ && val.end < BLOCK_END (SYMBOL_BLOCK_VALUE (sym)))
+ {
+ /* First pc of next line */
+ pc = val.end;
+ /* Recalculate the line number (might not be N+1). */
+ val = find_pc_line (pc, 0);
+ }
+ val.pc = pc;
+#endif
+ values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line));
+ values.sals[0] = val;
+ values.nelts = 1;
+
+ /* I think this is always the same as the line that
+ we calculate above, but the general principle is
+ "trust the symbols more than stuff like
+ SKIP_PROLOGUE". */
+ if (SYMBOL_LINE (sym) != 0)
+ values.sals[0].line = SYMBOL_LINE (sym);
+
+ /* 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) + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ 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;
+ register CORE_ADDR pc;
+ 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("[0] cancel\n[1] all\n");
+ while (i < nelts)
+ {
+ if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK)
+ {
+ /* Arg is the name of a function */
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym_arr[i]))
+ + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (pc);
+ values.sals[i] = find_pc_line (pc, 0);
+ values.sals[i].pc = (values.sals[i].end && values.sals[i].pc != pc) ?
+ values.sals[i].end : pc;
+ printf("[%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 ("?HERE\n");
+ i++;
+ }
+
+ if ((prompt = getenv ("PS2")) == NULL)
+ {
+ prompt = ">";
+ }
+ printf("%s ",prompt);
+ fflush(stdout);
+
+ args = command_line_input ((char *) NULL, 0);
+
+ 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 ("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 ("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, 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)
+ char *regexp;
+ int class;
+ int bpt;
+{
+ 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_text, mst_abs, mst_unknown};
+ enum minimal_symbol_type ourtype = types[class];
+ enum minimal_symbol_type ourtype2 = types2[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)
+ {
+ 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. */
+ char *string =
+ (char *) alloca (strlen (s->filename)
+ + strlen (SYMBOL_NAME(sym))
+ + 2);
+ strcpy (string, s->filename);
+ strcat (string, ":");
+ strcat (string, SYMBOL_NAME(sym));
+ break_command (string, 0);
+ }
+ }
+ else if (!found_in_file)
+ {
+ fputs_filtered ("\nFile ", stdout);
+ fputs_filtered (s->filename, stdout);
+ fputs_filtered (":\n", 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, 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)),
+ 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),
+ stdout, 0, 0);
+ c_type_print_varspec_prefix (TYPE_FN_FIELD_TYPE(t, i),
+ stdout, 0);
+ sprintf (buf, " %s::", type_name_no_tag (t));
+ cp_type_print_method_args (TYPE_FN_FIELD_ARGS (t, i),
+ buf, name, 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)
+ {
+ 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);
+}
+
+static void
+functions_info (regexp, from_tty)
+ char *regexp;
+ int from_tty;
+{
+ list_symbols (regexp, 1, 0);
+}
+
+static void
+types_info (regexp, from_tty)
+ char *regexp;
+ int from_tty;
+{
+ list_symbols (regexp, 2, 0);
+}
+
+#if 0
+/* Tiemann says: "info methods was never implemented." */
+static void
+methods_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 3, 0);
+}
+#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);
+}
+
+
+/* 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..9570b39
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/symtab.h
@@ -0,0 +1,1124 @@
+/* Symbol table definitions for GDB.
+ Copyright (C) 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 (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
+
+/* 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. */
+
+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
+ {
+ long value;
+
+ struct block *block;
+
+ char *bytes;
+
+ CORE_ADDR address;
+
+ /* for opaque typedef struct chain */
+
+ struct symbol *chain;
+ }
+ value;
+
+ /* Record the source code language that applies to this symbol.
+ This is used to select one of the fields from the language specific
+ union below. */
+
+ enum language language;
+
+ /* 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;
+
+ /* 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). */
+
+ int section;
+};
+
+#define SYMBOL_NAME(symbol) (symbol)->ginfo.name
+#define SYMBOL_VALUE(symbol) (symbol)->ginfo.value.value
+#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
+
+
+extern int demangle; /* We reference it, so go ahead and declare it. */
+
+/* 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))
+
+/* From utils.c. */
+extern int demangle;
+extern int asm_demangle;
+
+/* 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) */
+ /* 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;
+
+};
+
+#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;
+
+ /* Name space code. */
+
+ enum namespace namespace;
+
+ /* Address class */
+
+ enum address_class class;
+
+ /* Data type of value */
+
+ struct type *type;
+
+ /* 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;
+
+ /* Address class (for info_symbols) */
+
+ enum address_class class;
+
+};
+
+#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). */
+
+#define VTBL_PREFIX_P(NAME) \
+ ((NAME)[3] == CPLUS_MARKER && !strncmp ((NAME), "_vt", 3))
+
+/* 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;
+
+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));
+
+/* 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));
+
+extern void
+prim_record_minimal_symbol_and_info PARAMS ((const char *, CORE_ADDR,
+ enum minimal_symbol_type,
+ char *info, int section));
+
+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 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 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 *, int, 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));
+
+#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 frame_file_full_name; /* in stack.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..ea1bd93
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/target.c
@@ -0,0 +1,789 @@
+/* Select target systems and architectures at runtime for GDB.
+ Copyright 1990, 1992, 1993 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"
+
+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;
+
+/* 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",
+ stdout);
+}
+
+/* Add a possible target architecture to the list. */
+
+void
+add_target (t)
+ struct target_ops *t;
+{
+ if (t->to_magic != OPS_MAGIC)
+ {
+ fprintf(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("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 ("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(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 from MEMADDR in target.
+ The read may also be terminated early by getting an error from target_xfer_
+ memory.
+ LEN is the size of the buffer pointed to by MYADDR. Note that a terminating
+ null will only be written if there is sufficient room. The return value is
+ is the number of bytes (including the null) actually transferred.
+*/
+
+int
+target_read_string (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ int tlen, origlen, offset, i;
+ char buf[4];
+
+ origlen = len;
+
+ while (len > 0)
+ {
+ tlen = MIN (len, 4 - (memaddr & 3));
+ offset = memaddr & 3;
+
+ if (target_xfer_memory (memaddr & ~3, buf, 4, 0))
+ return origlen - len;
+
+ for (i = 0; i < tlen; i++)
+ {
+ *myaddr++ = buf[i + offset];
+ if (buf[i + offset] == '\000')
+ return (origlen - len) + i + 1;
+ }
+
+ memaddr += tlen;
+ len -= tlen;
+ }
+ return origlen;
+}
+
+/* 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 ("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("\tWhile running this, gdb does not access memory from...\n");
+ printf("%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.");
+ }
+}
+
+/* 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);
+}
+
+/* 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)
+ {
+ if ((*t)->to_stratum == core_stratum)
+ {
+ runable = *t;
+ ++count;
+ }
+ }
+
+ return(count == 1 ? runable : NULL);
+}
+
+/* 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);
+}
diff --git a/gnu/usr.bin/gdb/gdb/target.h b/gnu/usr.bin/gdb/gdb/target.h
new file mode 100644
index 0000000..c112b4a
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/target.h
@@ -0,0 +1,465 @@
+/* Interface between GDB and target environments, including files and processes
+ Copyright 1990, 1991, 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. */
+
+#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 */
+ process_stratum /* Executing processes */
+};
+
+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, int));
+ int (*to_wait) PARAMS ((int, int *));
+ 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));
+
+ 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 value (e.g. SIGINT) to be
+ given to the target, or zero for no signal. */
+
+#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. */
+
+#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));
+
+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)
+
+/* 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 sec_ptr; /* BFD section pointer */
+ 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));
+
+#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..f14b41f
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/thread.c
@@ -0,0 +1,248 @@
+/* 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 <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
+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 ()
+{
+ add_info ("threads", info_threads_command,
+ "IDs of currently known threads.");
+ add_com ("thread", class_info, thread_command,
+ "Use this command to switch between threads.\n\
+The new thread ID must be currently known.");
+}
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..f80f519
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/tm-i386v.h
@@ -0,0 +1,309 @@
+/* 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. */
+
+#define REGISTER_TYPE long
+
+/* 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
+
+/* Nonzero if register N requires conversion
+ from raw format to virtual format. */
+
+#define REGISTER_CONVERTIBLE(N) (0)
+
+/* Convert data from raw format for register REGNUM
+ to virtual format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \
+ {memcpy ((TO), (FROM), 4);}
+
+/* Convert data from virtual format for register REGNUM
+ to raw format for register REGNUM. */
+
+#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \
+ {memcpy ((TO), (FROM), 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 */
+
+/* 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..25b66c7
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/tm.h
@@ -0,0 +1,76 @@
+/* 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. */
+
+/* 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. */
+#undef NUM_REGS
+#define NUM_REGS 10
+
+/* 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(FRAME)
+#define FRAME_SAVED_PC(FRAME) \
+ (((FRAME)->signal_handler_caller \
+ ? sigtramp_saved_pc (FRAME) \
+ : read_memory_integer ((FRAME)->frame + 4, 4)) \
+ )
diff --git a/gnu/usr.bin/gdb/gdb/typeprint.c b/gnu/usr.bin/gdb/gdb/typeprint.c
new file mode 100644
index 0000000..5e13e07
--- /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;
+ 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 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), "", 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, "", 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;
+ 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.");
+ }
+ fflush (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 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 STRUCTNAME\"\n\
+or \"union UNIONNAME\" or \"enum ENUMNAME\".\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..e6740db
--- /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, 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..38010e3
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/utils.c
@@ -0,0 +1,1547 @@
+/* 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 "terminal.h" /* For job_control */
+#include "bfd.h"
+#include "target.h"
+#include "demangle.h"
+#include "expression.h"
+#include "language.h"
+
+/* 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 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 */
+ fflush (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 */
+ fflush (stdout);
+ if (warning_pre_print)
+ fprintf (stderr, warning_pre_print);
+ string = va_arg (args, char *);
+ vfprintf (stderr, string, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+}
+
+/* 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;
+
+ va_start (args);
+ target_terminal_ours ();
+ wrap_here(""); /* Force out any buffered output */
+ fflush (stdout);
+ if (error_pre_print)
+ fprintf_filtered (stderr, error_pre_print);
+ string = va_arg (args, char *);
+ vfprintf_filtered (stderr, string, args);
+ fprintf_filtered (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 (stderr, "\ngdb: ");
+ vfprintf (stderr, string, args);
+ fprintf (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 (stderr, "\ngdb internal error: ");
+ vfprintf (stderr, string, args);
+ fprintf (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_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);
+
+ fprintf (stderr, "%s.\n", combined);
+}
+
+/* Control C eventually causes this to be called, at a convenient time. */
+
+void
+quit ()
+{
+ serial_t stdout_serial = serial_fdopen (1);
+
+ target_terminal_ours ();
+ wrap_here ((char *)0); /* Force out any pending output */
+
+ SERIAL_FLUSH_OUTPUT (stdout_serial);
+
+ SERIAL_UN_FDOPEN (stdout_serial);
+
+ /* Don't use *_filtered; we don't want to prompt the user to continue. */
+ if (error_pre_print)
+ fprintf (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 (stderr, "Quit\n");
+ else
+ fprintf (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;
+ else if (k == 2)
+ immediate_quit = 1;
+ quit ();
+ }
+}
+
+#endif
+
+/* Control C comes here */
+
+void
+request_quit (signo)
+ int signo;
+{
+ quit_flag = 1;
+
+#ifdef USG
+ /* Restore the signal handler. */
+ signal (signo, request_quit);
+#endif
+
+ if (immediate_quit)
+ quit ();
+}
+
+
+/* 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);
+}
+
+/* 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;
+
+ /* 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 */
+ fflush (stdout);
+ va_start (args);
+ ctlstr = va_arg (args, char *);
+ vfprintf_filtered (stdout, ctlstr, args);
+ va_end (args);
+ printf_filtered ("(y or n) ");
+ fflush (stdout);
+ answer = fgetc (stdin);
+ clearerr (stdin); /* in case of C-d */
+ if (answer == EOF) /* C-d */
+ return 1;
+ 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')
+ return 1;
+ if (answer == 'N')
+ return 0;
+ printf_filtered ("Please answer y or n.\n");
+ }
+}
+
+
+/* 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;
+
+ /* 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. */
+ ignore =
+ gdb_readline ("---Type <return> to continue, or q <return> to quit---");
+ 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;
+{
+ if (wrap_buffer[0])
+ {
+ *wrap_pointer = '\0';
+ fputs (wrap_buffer, 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");
+ }
+}
+
+/* Like fputs but pause after every screenful, and can wrap at points
+ other than the final character of a line.
+ Unlike fputs, fputs_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
+ (since prompt_for_continue may do so) so this routine should not be
+ called when cleanups are not in place. */
+
+void
+fputs_filtered (linebuffer, stream)
+ const char *linebuffer;
+ FILE *stream;
+{
+ const char *lineptr;
+
+ if (linebuffer == 0)
+ return;
+
+ /* Don't do any filtering if it is disabled. */
+ if (stream != stdout
+ || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX))
+ {
+ fputs (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 (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
+ putc ('\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
+ putc (*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)
+ putc ('\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 (wrap_indent, stream);
+ *wrap_pointer = '\0'; /* Null-terminate saved stuff */
+ fputs (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++;
+ putc ('\n', stream);
+ lineptr++;
+ }
+ }
+}
+
+/* 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,
+ print out a pause message and do a gdb_readline 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 that this routine has a restriction that the length of the
+ final output line must be less than 255 characters *or* it must be
+ less than twice the size of the format string. This is a very
+ arbitrary restriction, but it is an internal restriction, so I'll
+ put it in. This means that the %s format specifier is almost
+ useless; unless the caller can GUARANTEE that the string is short
+ enough, fputs_filtered should be used instead.
+
+ 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. */
+
+#define MIN_LINEBUF 255
+
+void
+vfprintf_filtered (stream, format, args)
+ FILE *stream;
+ char *format;
+ va_list args;
+{
+ char line_buf[MIN_LINEBUF+10];
+ char *linebuffer = line_buf;
+ int format_length;
+
+ format_length = strlen (format);
+
+ /* Reallocate buffer to a larger size if this is necessary. */
+ if (format_length * 2 > MIN_LINEBUF)
+ {
+ linebuffer = alloca (10 + format_length * 2);
+ }
+
+ /* This won't blow up if the restrictions described above are
+ followed. */
+ vsprintf (linebuffer, format, args);
+
+ fputs_filtered (linebuffer, stream);
+}
+
+void
+vprintf_filtered (format, args)
+ char *format;
+ va_list args;
+{
+ vfprintf_filtered (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 *);
+
+ /* This won't blow up if the restrictions described above are
+ followed. */
+ vfprintf_filtered (stream, format, args);
+ va_end (args);
+}
+
+/* Like fprintf_filtered, but prints it's result indent.
+ 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);
+
+ /* This won't blow up if the restrictions described above are
+ followed. */
+ 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 (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, stdout);
+ vfprintf_filtered (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, 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 (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..3711a15
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/valarith.c
@@ -0,0 +1,969 @@
+/* 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 <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
+value_subscripted_rvalue PARAMS ((value, value));
+
+
+value
+value_add (arg1, arg2)
+ value arg1, arg2;
+{
+ register value 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
+value_sub (arg1, arg2)
+ value 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
+value_subscript (array, idx)
+ value array, idx;
+{
+ int lowerbound;
+ value bound;
+ struct type *range_type;
+
+ COERCE_REF (array);
+
+ if (TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_ARRAY)
+ {
+ 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);
+ }
+ }
+ 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
+value_subscripted_rvalue (array, idx)
+ value 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 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 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 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
+value_x_binop (arg1, arg2, op, otherop)
+ value arg1, arg2;
+ enum exp_opcode op, otherop;
+{
+ value * 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 *) alloca (sizeof (value) * 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
+value_x_unop (arg1, op)
+ value arg1;
+ enum exp_opcode op;
+{
+ value * argvec;
+ char *ptr;
+ char 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 *) alloca (sizeof (value) * 3);
+ argvec[1] = value_addr (arg1);
+ argvec[2] = 0;
+
+ /* make the right function name up */
+ strcpy(tstr,"operator__");
+ ptr = tstr+8;
+ 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
+value_concat (arg1, arg2)
+ value arg1, arg2;
+{
+ register value 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
+value_binop (arg1, arg2, op)
+ value arg1, arg2;
+ enum exp_opcode op;
+{
+ register value 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 (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))
+ 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)
+ {
+ 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);
+ SWAP_TARGET_AND_HOST (&v, sizeof (v));
+ *(double *) VALUE_CONTENTS_RAW (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.");
+ }
+
+ val = allocate_value (BUILTIN_TYPE_UNSIGNED_LONGEST);
+ 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.");
+ }
+
+ val = allocate_value (BUILTIN_TYPE_LONGEST);
+ 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 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 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 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
+value_neg (arg1)
+ register value 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
+value_complement (arg1)
+ register value 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));
+}
+
diff --git a/gnu/usr.bin/gdb/gdb/valops.c b/gnu/usr.bin/gdb/gdb/valops.c
new file mode 100644
index 0000000..dc4d82a
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/valops.c
@@ -0,0 +1,1819 @@
+/* Perform non-arithmetic operations on values, 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. */
+
+#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 t2[]));
+
+static CORE_ADDR
+find_function_addr PARAMS ((value, struct type **));
+
+static CORE_ADDR
+value_push PARAMS ((CORE_ADDR, value));
+
+static CORE_ADDR
+value_arg_push PARAMS ((CORE_ADDR, value));
+
+static value
+search_struct_field PARAMS ((char *, value, int, struct type *, int));
+
+static value
+search_struct_method PARAMS ((char *, value *, value *, 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 val;
+ register struct symbol *sym;
+ struct minimal_symbol *msymbol;
+ struct type *type;
+ value 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
+value_cast (type, arg2)
+ struct type *type;
+ register value 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 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 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
+value_zero (type, lv)
+ struct type *type;
+ enum lval_type lv;
+{
+ register value 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
+value_at (type, addr)
+ struct type *type;
+ CORE_ADDR addr;
+{
+ register value 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
+value_at_lazy (type, addr)
+ struct type *type;
+ CORE_ADDR addr;
+{
+ register value 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 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
+value_assign (toval, fromval)
+ register value toval, fromval;
+{
+ register struct type *type = VALUE_TYPE (toval);
+ register value val;
+ char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+ int use_buffer = 0;
+
+ COERCE_ARRAY (fromval);
+ COERCE_REF (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. */
+
+ if (VALUE_REGNO (toval) >= 0
+ && REGISTER_CONVERTIBLE (VALUE_REGNO (toval)))
+ {
+ int regno = VALUE_REGNO (toval);
+ if (VALUE_TYPE (fromval) != REGISTER_VIRTUAL_TYPE (regno))
+ fromval = value_cast (REGISTER_VIRTUAL_TYPE (regno), fromval);
+ memcpy (virtual_buffer, VALUE_CONTENTS (fromval),
+ REGISTER_VIRTUAL_SIZE (regno));
+ REGISTER_CONVERT_TO_RAW (regno, virtual_buffer, raw_buffer);
+ use_buffer = REGISTER_RAW_SIZE (regno);
+ }
+
+ 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))
+ {
+ int v; /* FIXME, this won't work for large bitfields */
+ read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ (char *) &v, sizeof v);
+ modify_field ((char *) &v, value_as_long (fromval),
+ VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+ write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ (char *)&v, sizeof v);
+ }
+ 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))
+ {
+ int v;
+
+ read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ (char *) &v, sizeof v);
+ modify_field ((char *) &v, value_as_long (fromval),
+ VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+ write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ (char *) &v, sizeof v);
+ }
+ 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
+ }
+ 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;
+ char *buffer = (char *) alloca (amount_to_copy);
+ 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 side of = operation 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);
+ }
+
+ /* FIXME: This loses if fromval is a different size than toval, for
+ example because fromval got cast in the REGISTER_CONVERTIBLE case
+ above. */
+ 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
+value_repeat (arg1, count)
+ value arg1;
+ int count;
+{
+ register value 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
+value_of_variable (var, b)
+ struct symbol *var;
+ struct block *b;
+{
+ value 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
+value_coerce_array (arg1)
+ value 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 = 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
+value_coerce_function (arg1)
+ value 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
+value_addr (arg1)
+ value 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 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
+value_ind (arg1)
+ value 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;
+ REGISTER_TYPE word;
+{
+ register int len = sizeof (REGISTER_TYPE);
+ 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 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
+value_arg_coerce (arg)
+ value 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 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 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
+call_function_by_hand (function, nargs, args)
+ value function;
+ int nargs;
+ value *args;
+{
+ register CORE_ADDR sp;
+ register int i;
+ CORE_ADDR start_sp;
+ /* CALL_DUMMY is an array of words (REGISTER_TYPE), but each word
+ is in host byte order. It is switched to target byte order before calling
+ FIX_CALL_DUMMY. */
+ static REGISTER_TYPE dummy[] = CALL_DUMMY;
+ REGISTER_TYPE dummy1[sizeof dummy / sizeof (REGISTER_TYPE)];
+ 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 (REGISTER_TYPE); i++)
+ store_unsigned_integer (&dummy1[i], sizeof (REGISTER_TYPE),
+ (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 need to pass a pointer
+ to the structure, not the structure itself. */
+ if (REG_STRUCT_HAS_ADDR (using_gcc))
+ for (i = nargs - 1; i >= 0; i--)
+ if (TYPE_CODE (VALUE_TYPE (args[i])) == TYPE_CODE_STRUCT)
+ {
+ 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);
+ 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
+call_function_by_hand (function, nargs, args)
+ value function;
+ int nargs;
+ value *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
+value_array (lowbound, highbound, elemvec)
+ int lowbound;
+ int highbound;
+ value *elemvec;
+{
+ int nelem;
+ int idx;
+ int typelength;
+ value 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
+value_string (ptr, len)
+ char *ptr;
+ int len;
+{
+ value 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 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++)
+ {
+ if (! t2[i])
+ return i+1;
+ if (TYPE_CODE (t1[i]) == TYPE_CODE_REF
+ /* We should be doing hairy argument matching, as below. */
+ && (TYPE_CODE (TYPE_TARGET_TYPE (t1[i]))
+ == TYPE_CODE (VALUE_TYPE (t2[i]))))
+ {
+ t2[i] = value_addr (t2[i]);
+ continue;
+ }
+
+ if (TYPE_CODE (t1[i]) == TYPE_CODE_PTR
+ && TYPE_CODE (VALUE_TYPE (t2[i])) == TYPE_CODE_ARRAY)
+ /* Array to pointer is a `trivial conversion' according to the ARM. */
+ continue;
+
+ /* 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
+search_struct_field (name, arg1, offset, type, looking_for_baseclass)
+ char *name;
+ register value 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 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 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 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
+search_struct_method (name, arg1p, args, offset, static_memfuncp, type)
+ char *name;
+ register value *arg1p, *args;
+ int offset, *static_memfuncp;
+ register struct type *type;
+{
+ int i;
+ static int name_matched = 0;
+
+ 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 (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)value_virtual_fn_field (arg1p, f, j, type, offset);
+ if (TYPE_FN_FIELD_STATIC_P (f, j) && static_memfuncp)
+ *static_memfuncp = 1;
+ return (value)value_fn_field (arg1p, f, j, type, offset);
+ }
+ j--;
+ }
+ }
+ }
+
+ for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+ {
+ value v;
+ 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) -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) -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
+value_struct_elt (argp, args, name, static_memfuncp, err)
+ register value *argp, *args;
+ char *name;
+ int *static_memfuncp;
+ char *err;
+{
+ register struct type *t;
+ value 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 == 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. */
+ return (value)value_fn_field (NULL, TYPE_FN_FIELDLIST1 (t, 0),
+ TYPE_FN_FIELDLIST_LENGTH (t, 0),
+ 0, 0);
+ }
+ else
+ {
+ error ("destructor should not have any argument");
+ }
+ }
+ else
+ v = search_struct_method (name, argp, args, 0, static_memfuncp, t);
+
+ if (v == (value) -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 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
+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 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)
+ {
+ if (STREQ (TYPE_FN_FIELDLIST_NAME (t, i), 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 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
+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 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..b805645
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/valprint.c
@@ -0,0 +1,1063 @@
+/* Print 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 <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 <errno.h>
+
+/* Prototypes for local functions */
+
+static void
+print_hex_chars PARAMS ((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));
+
+static void
+value_print_array_elements PARAMS ((value, FILE *, int, enum val_prettyprint));
+
+/* 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;
+
+int prettyprint_structs; /* Controls pretty printing of structures */
+int prettyprint_arrays; /* Controls pretty printing of 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;
+ 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. Typical types that my be stubs
+ are structs, unions, and C++ methods. */
+
+ check_stub_type (type);
+ if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+ {
+ fprintf_filtered (stream, "<incomplete type>");
+ fflush (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 val;
+ FILE *stream;
+ int format;
+ enum val_prettyprint pretty;
+{
+ register unsigned int n, typelen;
+
+ if (val == 0)
+ {
+ printf_filtered ("<address of value unknown>");
+ return 0;
+ }
+ if (VALUE_OPTIMIZED_OUT (val))
+ {
+ printf_filtered ("<value optimized out>");
+ return 0;
+ }
+
+ /* 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))
+ {
+ n = VALUE_REPETITIONS (val);
+ 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));
+ }
+}
+
+/* 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;
+ 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))
+ {
+ /* We can print it in decimal. */
+ print_longest (stream, 'u', 0,
+ unpack_long (BUILTIN_TYPE_LONGEST, first_addr));
+ }
+ 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(). USE_LOCAL says whether or not to call the
+ local formatting routine to get the format. */
+
+void
+print_longest (stream, format, use_local, val_long)
+ 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') && 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 */
+}
+
+/* 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;
+ 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. */
+
+ {
+ 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 == sizeof (float))
+ {
+ /* It's single precision. */
+ memcpy ((char *) &low, valaddr, sizeof (low));
+ /* target -> host. */
+ SWAP_TARGET_AND_HOST (&low, sizeof (float));
+ nonnegative = low >= 0;
+ is_nan = ((((low >> 23) & 0xFF) == 0xFF)
+ && 0 != (low & 0x7FFFFF));
+ low &= 0x7fffff;
+ high = 0;
+ }
+ else
+ {
+ /* It's double precision. Get the high and low words. */
+
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+ memcpy (&low, valaddr+4, sizeof (low));
+ memcpy (&high, valaddr+0, sizeof (high));
+#else
+ memcpy (&low, valaddr+0, sizeof (low));
+ memcpy (&high, valaddr+4, sizeof (high));
+#endif
+ SWAP_TARGET_AND_HOST (&low, sizeof (low));
+ SWAP_TARGET_AND_HOST (&high, sizeof (high));
+ nonnegative = high >= 0;
+ is_nan = (((high >> 20) & 0x7ff) == 0x7ff
+ && ! ((((high & 0xfffff) == 0)) && (low == 0)));
+ high &= 0xfffff;
+ }
+
+ 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)
+ 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;
+ 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;
+
+ 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);
+ fprintf_filtered (stream, " <repeats %u times>", reps);
+ i = rep1 - 1;
+ things_printed += repeat_count_threshold;
+ }
+ else
+ {
+ val_print (elttype, valaddr + i * eltlen, 0, stream, format,
+ deref_ref, recurse + 1, pretty);
+ things_printed++;
+ }
+ }
+ if (i < len)
+ {
+ fprintf_filtered (stream, "...");
+ }
+}
+
+static void
+value_print_array_elements (val, stream, format, pretty)
+ value val;
+ 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 (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. */
+
+int
+val_print_string (addr, len, stream)
+ CORE_ADDR addr;
+ unsigned int len;
+ 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 DEFAULT_PRINT_MAX and fetchlimit. */
+
+ chunksize = (len == 0 ? min (PRINT_MAX_DEFAULT, 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;
+ do {
+ addr++;
+ bufptr++;
+ } while (bufptr < limit && *(bufptr - 1) != '\0');
+ }
+ } while (errcode == 0 /* no error */
+ && bufptr < buffer + fetchlimit /* no overrun */
+ && !(len == 0 && *(bufptr - 1) == '\0')); /* no null term */
+
+ /* 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 - 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 (addressprint)
+ {
+ fputs_filtered (" ", stream);
+ }
+ LA_PRINT_STRING (stream, buffer, bufptr - buffer, force_ellipsis);
+
+ if (errcode != 0 && force_ellipsis)
+ {
+ if (errcode == EIO)
+ {
+ fprintf_filtered (stream,
+ " <Address 0x%lx out of bounds>",
+ (unsigned long) addr);
+ }
+ else
+ {
+ error ("Error reading memory address 0x%lx: %s.",
+ (unsigned long) addr,
+ safe_strerror (errcode));
+ }
+ }
+ fflush (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 (
+"\"set print\" must be followed by the name of a print subcommand.\n");
+ help_list (setprintlist, "set print ", -1, 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 ("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..5918def
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/valprint.h
@@ -0,0 +1,40 @@
+/* Declarations for value printing routines 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. */
+
+
+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 void
+val_print_array_elements PARAMS ((struct type *, char *, CORE_ADDR, FILE *,
+ int, int, int, enum val_prettyprint, int));
+
+extern void
+val_print_type_code_int PARAMS ((struct type *, char *, 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..b8e1676
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/value.h
@@ -0,0 +1,502 @@
+/* Definitions for values of C expressions, 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. */
+
+#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;
+ /* 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;
+#ifdef CC_HAS_LONG_LONG
+ long long force_longlong_align;
+#endif
+ } aligner;
+
+ };
+
+typedef struct value *value;
+
+#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 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 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, FILE *, int));
+
+extern LONGEST
+value_as_long PARAMS ((value val));
+
+extern double
+value_as_double PARAMS ((value val));
+
+extern CORE_ADDR
+value_as_pointer PARAMS ((value 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 value_from_longest PARAMS ((struct type *type, LONGEST num));
+
+extern value value_from_double PARAMS ((struct type *type, double num));
+
+extern value value_at PARAMS ((struct type *type, CORE_ADDR addr));
+
+extern value value_at_lazy PARAMS ((struct type *type, CORE_ADDR addr));
+
+/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */
+extern value value_from_register PARAMS ((struct type *type, int regnum,
+ struct frame_info * frame));
+
+extern value value_of_variable PARAMS ((struct symbol *var, struct block *b));
+
+extern value 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 read_var_value PARAMS ((struct symbol *var,
+ struct frame_info *frame));
+
+/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */
+extern value locate_var_value PARAMS ((struct symbol *var,
+ struct frame_info *frame));
+
+extern value allocate_value PARAMS ((struct type *type));
+
+extern value allocate_repeat_value PARAMS ((struct type *type, int count));
+
+extern value value_mark PARAMS ((void));
+
+extern void value_free_to_mark PARAMS ((value mark));
+
+extern value value_string PARAMS ((char *ptr, int len));
+
+extern value value_array PARAMS ((int lowbound, int highbound,
+ value *elemvec));
+
+extern value value_concat PARAMS ((value arg1, value arg2));
+
+extern value value_binop PARAMS ((value arg1, value arg2, enum exp_opcode op));
+
+extern value value_add PARAMS ((value arg1, value arg2));
+
+extern value value_sub PARAMS ((value arg1, value arg2));
+
+extern value value_coerce_array PARAMS ((value arg1));
+
+extern value value_coerce_function PARAMS ((value arg1));
+
+extern value value_ind PARAMS ((value arg1));
+
+extern value value_addr PARAMS ((value arg1));
+
+extern value value_assign PARAMS ((value toval, value fromval));
+
+extern value value_neg PARAMS ((value arg1));
+
+extern value value_complement PARAMS ((value arg1));
+
+extern value value_struct_elt PARAMS ((value *argp, value *args, char *name,
+ int *static_memfuncp, char *err));
+
+extern value value_struct_elt_for_reference PARAMS ((struct type *domain,
+ int offset,
+ struct type *curtype,
+ char *name,
+ struct type *intype));
+
+extern value value_field PARAMS ((value arg1, int fieldno));
+
+extern value value_primitive_field PARAMS ((value arg1, int offset,
+ int fieldno,
+ struct type *arg_type));
+
+extern value value_cast PARAMS ((struct type *type, value arg2));
+
+extern value value_zero PARAMS ((struct type *type, enum lval_type lv));
+
+extern value value_repeat PARAMS ((value arg1, int count));
+
+extern value value_subscript PARAMS ((value array, value idx));
+
+extern value value_from_vtable_info PARAMS ((value arg, struct type *type));
+
+extern value value_being_returned PARAMS ((struct type *valtype,
+ char retbuf[REGISTER_BYTES],
+ int struct_return));
+
+extern int
+using_struct_return PARAMS ((value function, CORE_ADDR funcaddr,
+ struct type *value_type, int gcc_p));
+
+extern void
+set_return_value PARAMS ((value val));
+
+extern value
+evaluate_expression PARAMS ((struct expression *exp));
+
+extern value
+evaluate_type PARAMS ((struct expression *exp));
+
+extern value
+parse_and_eval PARAMS ((char *exp));
+
+extern value
+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
+access_value_history PARAMS ((int num));
+
+extern value
+value_of_internalvar PARAMS ((struct internalvar *var));
+
+extern void
+set_internalvar PARAMS ((struct internalvar *var, value val));
+
+extern void
+set_internalvar_component PARAMS ((struct internalvar *var, int offset,
+ int bitpos, int bitsize,
+ value newvalue));
+
+extern struct internalvar *
+lookup_internalvar PARAMS ((char *name));
+
+extern int
+value_equal PARAMS ((value arg1, value arg2));
+
+extern int
+value_less PARAMS ((value arg1, value arg2));
+
+extern int
+value_logical_not PARAMS ((value arg1));
+
+/* C++ */
+
+extern value
+value_of_this PARAMS ((int complain));
+
+extern value
+value_x_binop PARAMS ((value arg1, value arg2, enum exp_opcode op,
+ enum exp_opcode otherop));
+
+extern value
+value_x_unop PARAMS ((value arg1, enum exp_opcode op));
+
+extern value
+value_fn_field PARAMS ((value *arg1p, struct fn_field *f, int j,
+ struct type* type, int offset));
+
+extern value
+value_virtual_fn_field PARAMS ((value *arg1p, struct fn_field *f, int j,
+ struct type *type, int offset));
+
+extern int
+binop_user_defined_p PARAMS ((enum exp_opcode op, value arg1, value arg2));
+
+extern int
+unop_user_defined_p PARAMS ((enum exp_opcode op, value 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 val));
+
+extern int
+record_latest_value PARAMS ((value 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, FILE *stream,
+ int show));
+
+extern char *
+baseclass_addr PARAMS ((struct type *type, int index, char *valaddr,
+ value *valuep, int *errp));
+
+extern void
+print_longest PARAMS ((FILE *stream, int format, int use_local,
+ LONGEST value));
+
+extern void
+print_floating PARAMS ((char *valaddr, struct type *type, FILE *stream));
+
+extern int
+value_print PARAMS ((value val, FILE *stream, int format,
+ enum val_prettyprint pretty));
+
+extern int
+val_print PARAMS ((struct type *type, char *valaddr, CORE_ADDR address,
+ 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, FILE *stream));
+
+/* FIXME: Assumes equivalence of "struct frame_info *" and "FRAME" */
+extern void
+print_variable_value PARAMS ((struct symbol *var, struct frame_info *frame,
+ FILE *stream));
+
+extern value
+value_arg_coerce PARAMS ((value));
+
+extern int
+check_field PARAMS ((value, const char *));
+
+extern void
+c_typedef_print PARAMS ((struct type *type, struct symbol *new, 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
+value_copy PARAMS ((value));
+
+extern int
+baseclass_offset PARAMS ((struct type *, int, value, int));
+
+/* From valops.c */
+
+extern value
+call_function_by_hand PARAMS ((value, int, value *));
+
+#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..a592f9e
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/values.c
@@ -0,0 +1,1502 @@
+/* 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
+value_headof PARAMS ((value, 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 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 all_values;
+
+/* Allocate a value that has the correct length for type TYPE. */
+
+value
+allocate_value (type)
+ struct type *type;
+{
+ register value val;
+
+ check_stub_type (type);
+
+ val = (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;
+ return val;
+}
+
+/* Allocate a value that has the correct length
+ for COUNT repetitions type TYPE. */
+
+value
+allocate_repeat_value (type, count)
+ struct type *type;
+ int count;
+{
+ register value val;
+
+ val = (value) 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
+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 mark;
+{
+ value 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 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 val;
+{
+ register value 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;
+ }
+ }
+}
+
+/* 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
+value_copy (arg)
+ value arg;
+{
+ register value 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);
+ 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 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);
+ VALUE_LVAL (val) = not_lval;
+ 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
+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 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 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, 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
+value_of_internalvar (var)
+ struct internalvar *var;
+{
+ register value 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 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 val;
+{
+#ifdef IS_TRAPPED_INTERNALVAR
+ if (IS_TRAPPED_INTERNALVAR (var->name))
+ SET_TRAPPED_INTERNALVAR (var, val, 0, 0, 0);
+#endif
+
+ free ((PTR)var->value);
+ var->value = 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 (var->value))
+ value_fetch_lazy (var->value);
+ release_value (var->value);
+}
+
+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, stdout, 0, Val_pretty_default);
+ printf_filtered ("\n");
+ }
+ if (!varseen)
+ printf ("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 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 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 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. */
+
+/* FIXME: This should be rewritten as a switch statement for speed and
+ ease of comprehension. */
+
+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);
+
+ if (code == TYPE_CODE_ENUM || code == TYPE_CODE_BOOL)
+ code = TYPE_CODE_INT;
+ if (code == TYPE_CODE_FLT)
+ {
+ if (len == sizeof (float))
+ {
+ float retval;
+ memcpy (&retval, valaddr, sizeof (retval));
+ SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
+ return retval;
+ }
+
+ if (len == sizeof (double))
+ {
+ double retval;
+ memcpy (&retval, valaddr, sizeof (retval));
+ SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
+ return retval;
+ }
+ else
+ {
+ error ("Unexpected type of floating point number.");
+ }
+ }
+ else if ((code == TYPE_CODE_INT || code == TYPE_CODE_CHAR) && nosign)
+ {
+ return extract_unsigned_integer (valaddr, len);
+ }
+ else if (code == TYPE_CODE_INT || code == TYPE_CODE_CHAR)
+ {
+ return extract_signed_integer (valaddr, len);
+ }
+ /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure
+ whether we want this to be true eventually. */
+ else if (code == TYPE_CODE_PTR || code == TYPE_CODE_REF)
+ {
+ return extract_address (valaddr, len);
+ }
+ else if (code == TYPE_CODE_MEMBER)
+ error ("not implemented: member types in unpack_long");
+
+ error ("Value not integer or pointer.");
+ return 0; /* For lint -- never reached */
+}
+
+/* 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;
+ }
+
+ if (len == sizeof (float))
+ {
+ float retval;
+ memcpy (&retval, valaddr, sizeof (retval));
+ SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
+ return retval;
+ }
+
+ if (len == sizeof (double))
+ {
+ double retval;
+ memcpy (&retval, valaddr, sizeof (retval));
+ SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
+ return retval;
+ }
+ else
+ {
+ error ("Unexpected type of floating point number.");
+ return 0; /* Placate lint. */
+ }
+ }
+ 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
+value_primitive_field (arg1, offset, fieldno, arg_type)
+ register value arg1;
+ int offset;
+ register int fieldno;
+ register struct type *arg_type;
+{
+ register value 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
+value_field (arg1, fieldno)
+ register value 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
+value_fn_field (arg1p, f, j, type, offset)
+ value *arg1p;
+ struct fn_field *f;
+ int j;
+ struct type *type;
+ int offset;
+{
+ register value 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) 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
+value_virtual_fn_field (arg1p, f, j, type, offset)
+ value *arg1p;
+ struct fn_field *f;
+ int j;
+ struct type *type;
+ int offset;
+{
+ value 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 entry, vfn, vtbl;
+ value 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);
+
+ /* Move the `this' pointer according to the virtual function table. */
+ VALUE_OFFSET (arg1) += value_as_long (value_field (entry, 0))/* + offset*/;
+
+ if (! VALUE_LAZY (arg1))
+ {
+ VALUE_LAZY (arg1) = 1;
+ value_fetch_lazy (arg1);
+ }
+
+ vfn = value_field (entry, 2);
+ /* 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
+value_headof (in_arg, btype, dtype)
+ value 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 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
+ || !VTBL_PREFIX_P (demangled_name = SYMBOL_NAME (msymbol)))
+ {
+ /* 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));
+ 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
+value_from_vtable_info (arg, type)
+ value 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 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 *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 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
+value_from_longest (type, num)
+ struct type *type;
+ register LONGEST num;
+{
+ register value 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:
+ 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
+value_from_double (type, num)
+ struct type *type;
+ double num;
+{
+ register value val = allocate_value (type);
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+
+ if (code == TYPE_CODE_FLT)
+ {
+ if (len == sizeof (float))
+ * (float *) VALUE_CONTENTS_RAW (val) = num;
+ else if (len == sizeof (double))
+ * (double *) VALUE_CONTENTS_RAW (val) = num;
+ else
+ error ("Floating type encountered with unexpected data length.");
+ }
+ else
+ error ("Unexpected type encountered for floating constant.");
+
+ /* num was in host byte order. So now put the value's contents
+ into target byte order. */
+ SWAP_TARGET_AND_HOST (VALUE_CONTENTS_RAW (val), len);
+
+ 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
+value_being_returned (valtype, retbuf, struct_return)
+ register struct type *valtype;
+ char retbuf[REGISTER_BYTES];
+ int struct_return;
+ /*ARGSUSED*/
+{
+ register value 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 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 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..d32e958
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/version.c
@@ -0,0 +1,3 @@
+char *version = "4.11";
+char *host_canonical = "i386-unknown-freebsd";
+char *target_canonical = "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..a72943c
--- /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..8d28df0
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/xm.h
@@ -0,0 +1,31 @@
+/* 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
+
+/* Get rid of any system-imposed stack limit if possible. */
+
+#define SET_STACK_LIMIT_HUGE
diff --git a/gnu/usr.bin/gdb/gdb/y.tab.h b/gnu/usr.bin/gdb/gdb/y.tab.h
new file mode 100644
index 0000000..62e0883
--- /dev/null
+++ b/gnu/usr.bin/gdb/gdb/y.tab.h
@@ -0,0 +1,65 @@
+#define INT 257
+#define HEX 258
+#define ERROR 259
+#define UINT 260
+#define M2_TRUE 261
+#define M2_FALSE 262
+#define CHAR 263
+#define FLOAT 264
+#define STRING 265
+#define NAME 266
+#define BLOCKNAME 267
+#define IDENT 268
+#define VARNAME 269
+#define TYPENAME 270
+#define SIZE 271
+#define CAP 272
+#define ORD 273
+#define HIGH 274
+#define ABS 275
+#define MIN_FUNC 276
+#define MAX_FUNC 277
+#define FLOAT_FUNC 278
+#define VAL 279
+#define CHR 280
+#define ODD 281
+#define TRUNC 282
+#define INC 283
+#define DEC 284
+#define INCL 285
+#define EXCL 286
+#define COLONCOLON 287
+#define LAST 288
+#define REGNAME 289
+#define INTERNAL_VAR 290
+#define ABOVE_COMMA 291
+#define ASSIGN 292
+#define LEQ 293
+#define GEQ 294
+#define NOTEQUAL 295
+#define IN 296
+#define OROR 297
+#define LOGICAL_AND 298
+#define DIV 299
+#define MOD 300
+#define UNARY 301
+#define DOT 302
+#define NOT 303
+#define QID 304
+typedef 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;
+ } YYSTYPE;
+extern YYSTYPE m2_lval;
diff --git a/gnu/usr.bin/gdb/getpagesize.h b/gnu/usr.bin/gdb/getpagesize.h
new file mode 100644
index 0000000..32adae6
--- /dev/null
+++ b/gnu/usr.bin/gdb/getpagesize.h
@@ -0,0 +1,25 @@
+#ifdef BSD
+#ifndef BSD4_1
+#define HAVE_GETPAGESIZE
+#endif
+#endif
+
+#ifndef HAVE_GETPAGESIZE
+
+#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 */
+
+#endif /* not HAVE_GETPAGESIZE */
+
diff --git a/gnu/usr.bin/gdb/infcmd.c b/gnu/usr.bin/gdb/infcmd.c
new file mode 100644
index 0000000..378784f
--- /dev/null
+++ b/gnu/usr.bin/gdb/infcmd.c
@@ -0,0 +1,1204 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)infcmd.c 6.4 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Memory-access and commands for inferior process, for GDB.
+ Copyright (C) 1986, 1987, 1988, 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. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "inferior.h"
+#include "environ.h"
+#include "value.h"
+
+#include <signal.h>
+#include <sys/param.h>
+
+extern char *sys_siglist[];
+
+#define ERROR_NO_INFERIOR \
+ if (inferior_pid == 0) error ("The program is not being run.");
+
+/* String containing arguments to give to the program,
+ with a space added at the front. Just a space 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. */
+
+int inferior_pid;
+
+/* Last signal that the inferior received (why it stopped). */
+
+int stop_signal;
+
+/* Address at which inferior stopped. */
+
+CORE_ADDR stop_pc;
+
+/* Stack frame when program stopped. */
+
+FRAME_ADDR stop_frame_address;
+
+/* Number of breakpoint it stopped at, or 0 if none. */
+
+int stop_breakpoint;
+
+/* 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.
+ -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;
+
+CORE_ADDR read_pc ();
+struct command_line *get_breakpoint_commands ();
+void breakpoint_clear_ignore_counts ();
+
+
+int
+have_inferior_p ()
+{
+ return inferior_pid != 0;
+}
+
+static void
+set_args_command (args)
+ char *args;
+{
+ free (inferior_args);
+ if (!args) args = "";
+ inferior_args = concat (" ", args, "");
+}
+
+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;
+{
+ extern char **environ;
+ register int i;
+ char *exec_file;
+ char *allargs;
+
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ extern int errno;
+
+ dont_repeat ();
+
+ if (inferior_pid)
+ {
+ extern int inhibit_confirm;
+ if (!(inhibit_confirm ||
+ query ("The program being debugged has been started already.\n\
+Start it from the beginning? ")))
+ error ("Program not restarted.");
+ kill_inferior ();
+ }
+
+#if 0
+ /* On the other hand, some users want to do
+ break open
+ ignore 1 40
+ run
+ So it's not clear what is best. */
+
+ /* It is confusing to the user for ignore counts to stick around
+ from previous runs of the inferior. So clear them. */
+ breakpoint_clear_ignore_counts ();
+#endif
+
+ exec_file = (char *) get_exec_file (1);
+
+ if (remote_debugging)
+ {
+ if (from_tty)
+ {
+ printf ("Starting program: %s\n", exec_file);
+ fflush (stdout);
+ }
+ }
+ else
+ {
+ if (args)
+ set_args_command (args);
+
+ if (from_tty)
+ {
+ printf ("Starting program: %s%s\n",
+ exec_file, inferior_args);
+ fflush (stdout);
+ }
+
+ allargs = concat ("exec ", exec_file, inferior_args);
+ inferior_pid = create_inferior (allargs, environ_vector (inferior_environ));
+ }
+
+ clear_proceed_status ();
+
+ start_inferior ();
+}
+
+void
+cont_command (proc_count_exp, from_tty)
+ char *proc_count_exp;
+ int from_tty;
+{
+ ERROR_NO_INFERIOR;
+
+ clear_proceed_status ();
+
+ /* If have argument, set proceed count of breakpoint we stopped at. */
+
+ if (stop_breakpoint > 0 && proc_count_exp)
+ {
+ set_ignore_count (stop_breakpoint,
+ parse_and_eval_address (proc_count_exp) - 1,
+ from_tty);
+ if (from_tty)
+ printf (" ");
+ }
+
+ if (from_tty)
+ printf ("Continuing.\n");
+
+ proceed (-1, -1, 0);
+}
+
+/* Step until outside of current statement. */
+static void step_1 ();
+
+static void
+step_command (count_string)
+{
+ step_1 (0, 0, count_string);
+}
+
+/* Likewise, but skip over subroutine calls as if single instructions. */
+
+static void
+next_command (count_string)
+{
+ step_1 (1, 0, count_string);
+}
+
+/* Likewise, but step only one instruction. */
+
+static void
+stepi_command (count_string)
+{
+ step_1 (0, 1, count_string);
+}
+
+static void
+nexti_command (count_string)
+{
+ 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;
+
+ ERROR_NO_INFERIOR;
+ count = count_string ? parse_and_eval_address (count_string) : 1;
+
+ for (; count > 0; count--)
+ {
+ clear_proceed_status ();
+
+ step_frame_address = FRAME_FP (get_current_frame ());
+
+ if (! single_inst)
+ {
+ find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
+ if (step_range_end == 0)
+ {
+ int misc;
+
+ misc = find_pc_misc_function (stop_pc);
+ terminal_ours ();
+ printf ("Current function has no line number information.\n");
+ fflush (stdout);
+
+ /* No info or after _etext ("Can't happen") */
+ if (misc == -1 || misc == misc_function_count - 1)
+ error ("No data available on pc function.");
+
+ printf ("Single stepping until function exit.\n");
+ fflush (stdout);
+
+ step_range_start = misc_function_vector[misc].address;
+ step_range_end = misc_function_vector[misc + 1].address;
+ }
+ }
+ else
+ {
+ /* Say we are stepping, but stop after one insn whatever it does.
+ Don't step through subroutine calls even to undebuggable
+ functions. */
+ step_range_start = step_range_end = 1;
+ if (!skip_subroutines)
+ step_over_calls = 0;
+ }
+
+ if (skip_subroutines)
+ step_over_calls = 1;
+
+ step_multi = (count > 1);
+ proceed (-1, -1, 1);
+ if (! stop_step)
+ break;
+ }
+}
+
+/* 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;
+
+ 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 (sals.sals);
+
+ if (sal.symtab == 0 && sal.pc == 0)
+ error ("No source file has been specified.");
+
+ if (sal.pc == 0)
+ sal.pc = find_line_pc (sal.symtab, sal.line);
+
+ {
+ struct symbol *fn = get_frame_function (get_current_frame ());
+ struct symbol *sfn = find_pc_function (sal.pc);
+ if (fn != 0 && sfn != fn
+ && ! query ("Line %d is not in `%s'. Jump anyway? ",
+ sal.line, SYMBOL_NAME (fn)))
+ error ("Not confirmed.");
+ }
+
+ if (sal.pc == 0)
+ error ("No line %d in file \"%s\".", sal.line, sal.symtab->filename);
+
+ addr = sal.pc;
+
+ clear_proceed_status ();
+
+ if (from_tty)
+ printf ("Continuing at 0x%x.\n", addr);
+
+ proceed (addr, 0, 0);
+}
+
+/* Continue program giving it specified signal. */
+
+static void
+signal_command (signum_exp, from_tty)
+ char *signum_exp;
+ int from_tty;
+{
+ register int signum;
+
+ dont_repeat (); /* Too dangerous. */
+ ERROR_NO_INFERIOR;
+
+ if (!signum_exp)
+ error_no_arg ("signal number");
+
+ signum = parse_and_eval_address (signum_exp);
+
+ clear_proceed_status ();
+
+ if (from_tty)
+ printf ("Continuing with signal %d.\n", signum);
+
+ proceed (stop_pc, signum, 0);
+}
+
+/* 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.
+ Otherwise, the caller never gets returned to. */
+
+/* 4 => return instead of letting the stack dummy run. */
+
+static int stack_dummy_testing = 0;
+
+void
+run_stack_dummy (addr, buffer)
+ CORE_ADDR addr;
+ REGISTER_TYPE *buffer;
+{
+ /* Now proceed, having reached the desired place. */
+ clear_proceed_status ();
+#ifdef notdef
+ if (stack_dummy_testing & 4)
+ {
+ POP_FRAME;
+ return;
+ }
+#endif
+ proceed (addr, 0, 0);
+
+ if (!stop_stack_dummy)
+ error ("Cannot continue previously requested operation.");
+
+ /* On return, the stack dummy has been popped already. */
+
+ read_register_bytes(0, buffer, REGISTER_BYTES);
+}
+
+/* Proceed until we reach the given line as argument or exit the
+ function. When called with no argument, 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.
+
+ The effect of this command with an argument is identical to setting
+ a momentary breakpoint at the line specified and executing
+ "finish".
+
+ Note that eventually this command should probably be changed so
+ that only source lines are printed out when we hit the breakpoint
+ we set. I'm going to postpone this until after a hopeful rewrite
+ of wait_for_inferior and the proceed status code. -- randy */
+
+void
+until_next_command (arg, from_tty)
+ char *arg;
+ 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)
+ {
+ int misc_func = find_pc_misc_function (pc);
+
+ if (misc_func != -1)
+ error ("Execution is not within a known function.");
+
+ step_range_start = misc_function_vector[misc_func].address;
+ 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 (-1, -1, 1);
+}
+
+void
+until_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (!have_inferior_p ())
+ error ("The program is not being run.");
+
+ if (arg)
+ until_break_command (arg, from_tty);
+ else
+ until_next_command (arg, 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;
+
+ if (!have_inferior_p ())
+ error ("The program is not being run.");
+ if (arg)
+ error ("The \"finish\" command does not take any arguments.");
+
+ 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;
+ set_momentary_breakpoint (sal, frame);
+
+ /* Find the function we will return from. */
+
+ fi = get_frame_info (selected_frame);
+ function = find_pc_function (fi->pc);
+
+ if (from_tty)
+ {
+ printf ("Run till exit from ");
+ print_selected_frame ();
+ }
+
+ proceed (-1, -1, 0);
+
+ if (stop_breakpoint == -3 && function != 0)
+ {
+ struct type *value_type;
+ register value val;
+ CORE_ADDR funcaddr;
+ extern char registers[];
+
+ 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, registers,
+ using_struct_return (function,
+ funcaddr,
+ value_type));
+
+ printf ("Value returned is $%d = ", record_latest_value (val));
+ value_print (val, stdout, 0, Val_no_prettyprint);
+ putchar ('\n');
+ }
+}
+
+static void
+program_info ()
+{
+ if (inferior_pid == 0)
+ {
+ printf ("The program being debugged is not being run.\n");
+ return;
+ }
+
+ printf ("Program being debugged is in process %d, stopped at 0x%x.\n",
+ inferior_pid, stop_pc);
+ if (stop_step)
+ printf ("It stopped after being stepped.\n");
+ else if (stop_breakpoint > 0)
+ printf ("It stopped at breakpoint %d.\n", stop_breakpoint);
+ else if (stop_signal)
+ printf ("It stopped with signal %d (%s).\n",
+ stop_signal, sys_siglist[stop_signal]);
+
+ printf ("\nType \"info stack\" or \"info reg\" for more information.\n");
+}
+
+static void
+environment_info (var)
+ char *var;
+{
+ if (var)
+ {
+ register char *val = get_in_environ (inferior_environ, var);
+ if (val)
+ printf ("%s = %s\n", var, val);
+ else
+ printf ("Environment variable \"%s\" not defined.\n", var);
+ }
+ else
+ {
+ register char **vector = environ_vector (inferior_environ);
+ while (*vector)
+ printf ("%s\n", *vector++);
+ }
+}
+
+static void
+set_environment_command (arg)
+ char *arg;
+{
+ 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 *) index (arg, '=');
+ val = (char *) index (arg, ' ');
+
+ if (p != 0 && val != 0)
+ {
+ /* We have both a space and an equals. If the space is before the
+ equals and the only thing between the two is more space, use
+ the equals */
+ if (p > val)
+ while (*val == ' ')
+ val++;
+
+ /* Take the smaller of the two. If there was space before the
+ "=", they will be the same right now. */
+ p = arg + min (p - arg, val - arg);
+ }
+ 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 ("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 ();
+ }
+
+ unset_in_environ (inferior_environ, var);
+}
+
+/* Read an integer from debugged memory, given address and number of bytes. */
+
+long
+read_memory_integer (memaddr, len)
+ CORE_ADDR memaddr;
+ int len;
+{
+ char cbuf;
+ short sbuf;
+ int ibuf;
+ long lbuf;
+ int result_err;
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+
+ if (len == sizeof (char))
+ {
+ result_err = read_memory (memaddr, &cbuf, len);
+ if (result_err)
+ error ("Error reading memory address 0x%x: %s (%d).",
+ memaddr, (result_err < sys_nerr ?
+ sys_errlist[result_err] :
+ "uknown error"), result_err);
+ return cbuf;
+ }
+ if (len == sizeof (short))
+ {
+ result_err = read_memory (memaddr, &sbuf, len);
+ if (result_err)
+ error ("Error reading memory address 0x%x: %s (%d).",
+ memaddr, (result_err < sys_nerr ?
+ sys_errlist[result_err] :
+ "uknown error"), result_err);
+ return sbuf;
+ }
+ if (len == sizeof (int))
+ {
+ result_err = read_memory (memaddr, &ibuf, len);
+ if (result_err)
+ error ("Error reading memory address 0x%x: %s (%d).",
+ memaddr, (result_err < sys_nerr ?
+ sys_errlist[result_err] :
+ "uknown error"), result_err);
+ return ibuf;
+ }
+ if (len == sizeof (lbuf))
+ {
+ result_err = read_memory (memaddr, &lbuf, len);
+ if (result_err)
+ error ("Error reading memory address 0x%x: %s (%d).",
+ memaddr, (result_err < sys_nerr ?
+ sys_errlist[result_err] :
+ "uknown error"), result_err);
+ return lbuf;
+ }
+ error ("Cannot handle integers of %d bytes.", len);
+}
+
+CORE_ADDR
+read_pc ()
+{
+ return (CORE_ADDR) read_register (PC_REGNUM);
+}
+
+void
+write_pc (val)
+ CORE_ADDR val;
+{
+ write_register (PC_REGNUM, (long) val);
+#ifdef NPC_REGNUM
+ write_register (NPC_REGNUM, (long) val+4);
+#endif
+}
+
+char *reg_names[] = REGISTER_NAMES;
+
+#if !defined (DO_REGISTERS_INFO)
+static void
+print_one_register(i)
+ int i;
+{
+ unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ unsigned char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+ REGISTER_TYPE val;
+
+ /* Get the data in raw format, then convert also to virtual format. */
+ read_relative_register_raw_bytes (i, raw_buffer);
+ REGISTER_CONVERT_TO_VIRTUAL (i, raw_buffer, virtual_buffer);
+
+ fputs_filtered (reg_names[i], stdout);
+ print_spaces_filtered (15 - strlen (reg_names[i]), stdout);
+
+ /* If virtual format is floating, print it that way. */
+ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT
+ && ! INVALID_FLOAT (virtual_buffer, REGISTER_VIRTUAL_SIZE (i)))
+ val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0,
+ stdout, 0, 1, 0, Val_pretty_default);
+ /* 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", virtual_buffer[j]);
+ }
+ /* Else print as integer in hex and in decimal. */
+ else
+ {
+ long val;
+
+ bcopy (virtual_buffer, &val, sizeof (long));
+ if (val == 0)
+ printf_filtered ("0");
+ else
+ printf_filtered ("0x%08x %d", val, val);
+ }
+
+ /* If register has different raw and virtual formats,
+ print the raw format in hex now. */
+
+ if (REGISTER_CONVERTIBLE (i))
+ {
+ register int j;
+
+ printf_filtered (" (raw 0x");
+ for (j = 0; j < REGISTER_RAW_SIZE (i); j++)
+ printf_filtered ("%02x", raw_buffer[j]);
+ printf_filtered (")");
+ }
+ printf_filtered ("\n");
+}
+
+
+/* Print out the machine register regnum. If regnum is -1,
+ print all registers.
+ 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 SPARC 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)
+ to provide that format. */
+static void
+do_registers_info (regnum, fpregs)
+ int regnum;
+ int fpregs;
+{
+ register int i;
+
+ if (regnum >= 0) {
+ print_one_register(regnum);
+ return;
+ }
+#ifdef notdef
+ printf_filtered (
+"Register Contents (relative to selected stack frame)\n\n");
+#endif
+ for (i = 0; i < NUM_REGS; i++)
+ if (TYPE_CODE(REGISTER_VIRTUAL_TYPE(i)) != TYPE_CODE_FLT ||
+ fpregs)
+ print_one_register(i);
+}
+#endif /* no DO_REGISTERS_INFO. */
+
+static void
+registers_info (addr_exp, fpregs)
+ char *addr_exp;
+ int fpregs;
+{
+ int regnum;
+
+ if (!have_inferior_p () && !have_core_file_p ())
+ error ("No inferior or core file");
+
+ if (addr_exp)
+ {
+ if (*addr_exp >= '0' && *addr_exp <= '9')
+ regnum = atoi (addr_exp);
+ else
+ {
+ register char *p = addr_exp;
+ if (p[0] == '$')
+ p++;
+ for (regnum = 0; regnum < NUM_REGS; regnum++)
+ if (!strcmp (p, reg_names[regnum]))
+ break;
+ if (regnum == NUM_REGS)
+ error ("%s: invalid register name.", addr_exp);
+ }
+ }
+ else
+ regnum = -1;
+
+#ifdef DO_REGISTERS_INFO
+ DO_REGISTERS_INFO(regnum);
+#else
+ do_registers_info(regnum, fpregs);
+#endif
+}
+
+static void
+all_registers_info (addr_exp)
+ char *addr_exp;
+{
+ registers_info(addr_exp, 1);
+}
+
+static void
+nofp_registers_info (addr_exp)
+ char *addr_exp;
+{
+ registers_info(addr_exp, 0);
+}
+
+
+#ifdef ATTACH_DETACH
+#define PROCESS_ATTACH_ALLOWED 1
+#else
+#define PROCESS_ATTACH_ALLOWED 0
+#endif
+/*
+ * 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 tracing it.
+ * For this to work, we must be able to send the process a
+ * signal and we must have the same effective uid as the program.
+ */
+static void
+attach_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *exec_file;
+ int pid;
+ int remote = 0;
+
+ dont_repeat();
+
+ if (!args)
+ error_no_arg ("process-id or device file to attach");
+
+ while (*args == ' ' || *args == '\t') args++;
+
+ if (args[0] < '0' || args[0] > '9')
+ remote = 1;
+ else
+#ifndef ATTACH_DETACH
+ error ("Can't attach to a process on this machine.");
+#else
+ pid = atoi (args);
+#endif
+
+ if (inferior_pid)
+ {
+ if (query ("A program is being debugged already. Kill it? "))
+ kill_inferior ();
+ else
+ error ("Inferior not killed.");
+ }
+
+ exec_file = (char *) get_exec_file (1);
+
+ if (from_tty)
+ {
+ if (remote)
+ printf ("Attaching remote machine\n");
+ else
+ printf ("Attaching program: %s pid %d\n",
+ exec_file, pid);
+ fflush (stdout);
+ }
+
+ if (remote)
+ {
+ remote_open (args, from_tty);
+ start_remote ();
+ }
+#ifdef ATTACH_DETACH
+ else
+ attach_program (pid);
+#endif
+}
+
+/*
+ * 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;
+{
+ int signal = 0;
+
+#ifdef ATTACH_DETACH
+ if (inferior_pid && !remote_debugging)
+ {
+ if (from_tty)
+ {
+ char *exec_file = (char *)get_exec_file (0);
+ if (exec_file == 0)
+ exec_file = "";
+ printf ("Detaching program: %s pid %d\n",
+ exec_file, inferior_pid);
+ fflush (stdout);
+ }
+ if (args)
+ signal = atoi (args);
+
+ detach (signal);
+ inferior_pid = 0;
+ }
+ else
+#endif
+ {
+ if (!remote_debugging)
+ error ("Not currently attached to subsidiary or remote process.");
+
+ if (args)
+ error ("Argument given to \"detach\" when remotely debugging.");
+
+ inferior_pid = 0;
+ remote_close (from_tty);
+ }
+}
+
+/* ARGSUSED */
+static void
+float_info (addr_exp)
+ char *addr_exp;
+{
+#ifdef FLOAT_INFO
+ FLOAT_INFO;
+#else
+ printf ("No floating point info available for this processor.\n");
+#endif
+}
+
+extern struct cmd_list_element *setlist, *deletelist;
+
+void
+_initialize_infcmd ()
+{
+ add_com ("tty", class_run, tty_command,
+ "Set terminal for future runs of program being debugged.");
+
+ add_cmd ("args", class_run, set_args_command,
+ "Specify 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);
+
+ add_info ("environment", 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.");
+
+ 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.",
+ &deletelist);
+
+ 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);
+
+#ifdef ATTACH_DETACH
+ add_com ("attach", class_run, attach_command,
+ "Attach to a process that was started up outside of GDB.\n\
+This 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\
+For a device file, the file must be a connection to a remote debug server.\n\n\
+Before using \"attach\", you must use the \"exec-file\" command\n\
+to specify the program running in the process,\n\
+and the \"symbol-file\" command to load its symbol table.");
+#else
+ add_com ("attach", class_run, attach_command,
+ "Attach to a process that was started up outside of GDB.\n\
+This commands takes as an argument the name of a device file.\n\
+This file must be a connection to a remote debug server.\n\n\
+Before using \"attach\", you must use the \"exec-file\" command\n\
+to specify the program running in the process,\n\
+and the \"symbol-file\" command to load its symbol table.");
+#endif
+ add_com ("detach", class_run, detach_command,
+ "Detach the process previously attached.\n\
+The process is no longer traced and continues its execution.");
+
+ 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 ("cont", class_run, cont_command,
+ "Continue program being debugged, after signal or breakpoint.\n\
+If proceeding from breakpoint, a number N may be used as an argument:\n\
+then the same breakpoint won't break until the Nth time it is reached.");
+ add_com_alias ("c", "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 registers and their contents, for selected stack frame.\n\
+Register name as argument means describe only that register.\n\
+(Doesn't display floating point registers; use 'info all-registers'.)\n");
+
+ add_info ("all-registers", all_registers_info,
+ "List of 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); /* By default, no args. */
+ inferior_environ = make_environ ();
+ init_environ (inferior_environ);
+}
+
diff --git a/gnu/usr.bin/gdb/inferior.h b/gnu/usr.bin/gdb/inferior.h
new file mode 100644
index 0000000..04c662e
--- /dev/null
+++ b/gnu/usr.bin/gdb/inferior.h
@@ -0,0 +1,142 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ *
+ * @(#)inferior.h 6.3 (Berkeley) 5/8/91
+ */
+
+/* Variables that describe the inferior process running under GDB:
+ Where it is, why it stopped, and how to step it.
+ Copyright (C) 1986, 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. */
+
+/*
+ * 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 {
+ int pc_changed;
+ int stop_signal;
+ int stop_pc;
+ int stop_frame_address;
+ int stop_breakpoint;
+ 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_after_attach;
+ FRAME_ADDR selected_frame_address;
+ int selected_level;
+ struct command_line *breakpoint_commands;
+ char register_context[REGISTER_BYTES];
+ int restore_stack_info;
+};
+
+void save_inferior_status (), restore_inferior_status ();
+
+/* 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;
+
+/* Nonzero if debugging a remote machine via a serial link or ethernet. */
+extern int remote_debugging;
+
+/* Routines for use in remote debugging. Documented in remote.c. */
+int remote_read_inferior_memory ();
+int remote_write_inferior_memory ();
+
+/* Last signal that the inferior received (why it stopped). */
+
+extern int stop_signal;
+
+/* Address at which inferior stopped. */
+
+extern CORE_ADDR stop_pc;
+
+/* Stack frame when program stopped. */
+
+extern FRAME_ADDR stop_frame_address;
+
+/* Number of breakpoint it stopped at, or 0 if none. */
+
+extern int stop_breakpoint;
+
+/* 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. */
+
+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;
+
+/* Save register contents here when about to pop a stack dummy frame. */
+
+extern char stop_registers[REGISTER_BYTES];
+
+/* Nonzero if pc has been changed by the debugger
+ since the inferior stopped. */
+
+extern int pc_changed;
+
+long read_memory_integer ();
diff --git a/gnu/usr.bin/gdb/inflow.c b/gnu/usr.bin/gdb/inflow.c
new file mode 100644
index 0000000..209fcf3
--- /dev/null
+++ b/gnu/usr.bin/gdb/inflow.c
@@ -0,0 +1,569 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)inflow.c 6.5 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Low level interface to ptrace, for GDB when running under Unix.
+ 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. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+/* Some USG-esque systems (some of which are BSD-esque enough so that USG
+ is not defined) want this header, and it won't do any harm. */
+#include <fcntl.h>
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+
+#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
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sgtty.h>
+#define TERMINAL struct sgttyb
+#endif
+
+#ifdef SET_STACK_LIMIT_HUGE
+#include <sys/time.h>
+#include <sys/resource.h>
+extern int original_stack_limit;
+#endif /* SET_STACK_LIMIT_HUGE */
+
+extern int errno;
+
+/* Nonzero if we are debugging an attached outside process
+ rather than an inferior. */
+
+int attach_flag;
+
+
+/* Record terminal status separately for debugger and inferior. */
+
+static TERMINAL sg_inferior;
+static TERMINAL sg_ours;
+
+static int tflags_inferior;
+static int tflags_ours;
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+static struct tchars tc_inferior;
+static struct tchars tc_ours;
+#endif
+
+#ifdef TIOCGLTC
+static struct ltchars ltc_inferior;
+static struct ltchars ltc_ours;
+#endif
+
+#ifdef TIOCLGET
+static int lmode_inferior;
+static int lmode_ours;
+#endif
+
+#ifdef TIOCGPGRP
+static int pgrp_inferior;
+static int pgrp_ours;
+#else
+static int (*sigint_ours) ();
+static int (*sigquit_ours) ();
+#endif /* TIOCGPGRP */
+
+/* Copy of inferior_io_terminal when inferior was last started. */
+static char *inferior_thisrun_terminal;
+
+static void terminal_ours_1 ();
+
+/* Nonzero if our terminal settings are in effect.
+ Zero if the inferior's settings are in effect. */
+static int terminal_is_ours;
+
+/* Initialize the terminal settings we record for the inferior,
+ before we actually run the inferior. */
+
+void
+terminal_init_inferior ()
+{
+ if (remote_debugging)
+ return;
+
+ sg_inferior = sg_ours;
+ tflags_inferior = tflags_ours;
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+ tc_inferior = tc_ours;
+#endif
+
+#ifdef TIOCGLTC
+ ltc_inferior = ltc_ours;
+#endif
+
+#ifdef TIOCLGET
+ lmode_inferior = lmode_ours;
+#endif
+
+#ifdef TIOCGPGRP
+ pgrp_inferior = inferior_pid;
+#endif /* TIOCGPGRP */
+
+ 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 (remote_debugging)
+ return;
+
+ if (terminal_is_ours) /* && inferior_thisrun_terminal == 0) */
+ {
+ fcntl (0, F_SETFL, tflags_inferior);
+ fcntl (0, F_SETFL, tflags_inferior);
+ ioctl (0, TIOCSETN, &sg_inferior);
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+ ioctl (0, TIOCSETC, &tc_inferior);
+#endif
+#ifdef TIOCGLTC
+ ioctl (0, TIOCSLTC, &ltc_inferior);
+#endif
+#ifdef TIOCLGET
+ ioctl (0, TIOCLSET, &lmode_inferior);
+#endif
+
+#ifdef TIOCGPGRP
+ ioctl (0, TIOCSPGRP, &pgrp_inferior);
+#else
+ sigint_ours = (int (*) ()) signal (SIGINT, SIG_IGN);
+ sigquit_ours = (int (*) ()) signal (SIGQUIT, SIG_IGN);
+#endif /* TIOCGPGRP */
+ }
+ 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 ()
+{
+ if (remote_debugging)
+ return;
+
+ 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 ()
+{
+ if (remote_debugging)
+ return;
+
+ terminal_ours_1 (0);
+}
+
+static void
+terminal_ours_1 (output_only)
+ int output_only;
+{
+#ifdef TIOCGPGRP
+ /* Ignore this signal since it will happen when we try to set the pgrp. */
+ void (*osigttou) ();
+#endif /* TIOCGPGRP */
+
+ if (!terminal_is_ours) /* && inferior_thisrun_terminal == 0) */
+ {
+ terminal_is_ours = 1;
+
+#ifdef TIOCGPGRP
+ osigttou = signal (SIGTTOU, SIG_IGN);
+
+ ioctl (0, TIOCGPGRP, &pgrp_inferior);
+ ioctl (0, TIOCSPGRP, &pgrp_ours);
+
+ signal (SIGTTOU, osigttou);
+#else
+ signal (SIGINT, sigint_ours);
+ signal (SIGQUIT, sigquit_ours);
+#endif /* TIOCGPGRP */
+
+ tflags_inferior = fcntl (0, F_GETFL, 0);
+ ioctl (0, TIOCGETP, &sg_inferior);
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+ ioctl (0, TIOCGETC, &tc_inferior);
+#endif
+#ifdef TIOCGLTC
+ ioctl (0, TIOCGLTC, &ltc_inferior);
+#endif
+#ifdef TIOCLGET
+ ioctl (0, TIOCLGET, &lmode_inferior);
+#endif
+ }
+
+#ifdef HAVE_TERMIO
+ sg_ours.c_lflag |= ICANON;
+ if (output_only && !(sg_inferior.c_lflag & ICANON))
+ sg_ours.c_lflag &= ~ICANON;
+#else /* not HAVE_TERMIO */
+ sg_ours.sg_flags &= ~RAW & ~CBREAK;
+ if (output_only)
+ sg_ours.sg_flags |= (RAW | CBREAK) & sg_inferior.sg_flags;
+#endif /* not HAVE_TERMIO */
+
+ fcntl (0, F_SETFL, tflags_ours);
+ fcntl (0, F_SETFL, tflags_ours);
+ ioctl (0, TIOCSETN, &sg_ours);
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+ ioctl (0, TIOCSETC, &tc_ours);
+#endif
+#ifdef TIOCGLTC
+ ioctl (0, TIOCSLTC, &ltc_ours);
+#endif
+#ifdef TIOCLGET
+ ioctl (0, TIOCLSET, &lmode_ours);
+#endif
+
+#ifdef HAVE_TERMIO
+ sg_ours.c_lflag |= ICANON;
+#else /* not HAVE_TERMIO */
+ sg_ours.sg_flags &= ~RAW & ~CBREAK;
+#endif /* not HAVE_TERMIO */
+}
+
+static void
+term_status_command ()
+{
+ register int i;
+
+ if (remote_debugging)
+ {
+ printf_filtered ("No terminal status when remote debugging.\n");
+ return;
+ }
+
+ printf_filtered ("Inferior's terminal status (currently saved by GDB):\n");
+
+#ifdef HAVE_TERMIO
+
+ printf_filtered ("fcntl flags = 0x%x, c_iflag = 0x%x, c_oflag = 0x%x,\n",
+ tflags_inferior, sg_inferior.c_iflag, sg_inferior.c_oflag);
+ printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n",
+ sg_inferior.c_cflag, sg_inferior.c_lflag, sg_inferior.c_line);
+ printf_filtered ("c_cc: ");
+ for (i = 0; (i < NCC); i += 1)
+ printf_filtered ("0x%x ", sg_inferior.c_cc[i]);
+ printf_filtered ("\n");
+
+#else /* not HAVE_TERMIO */
+
+ printf_filtered ("fcntl flags = 0x%x, sgttyb.sg_flags = 0x%x, owner pid = %d.\n",
+ tflags_inferior, sg_inferior.sg_flags, pgrp_inferior);
+
+#endif /* not HAVE_TERMIO */
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+ printf_filtered ("tchars: ");
+ for (i = 0; i < sizeof (struct tchars); i++)
+ printf_filtered ("0x%x ", ((char *)&tc_inferior)[i]);
+ printf_filtered ("\n");
+#endif
+
+#ifdef TIOCGLTC
+ printf_filtered ("ltchars: ");
+ for (i = 0; i < sizeof (struct ltchars); i++)
+ printf_filtered ("0x%x ", ((char *)&ltc_inferior)[i]);
+ printf_filtered ("\n");
+ ioctl (0, TIOCSLTC, &ltc_ours);
+#endif
+
+#ifdef TIOCLGET
+ printf_filtered ("lmode: %x\n", lmode_inferior);
+#endif
+}
+
+static void
+new_tty (ttyname)
+ char *ttyname;
+{
+ register int tty;
+ register int fd;
+
+#ifdef TIOCNOTTY
+ /* Disconnect the child process from our controlling terminal. */
+ tty = open("/dev/tty", O_RDWR);
+ if (tty > 0)
+ {
+ ioctl(tty, TIOCNOTTY, 0);
+ close(tty);
+ }
+#endif
+
+ /* Now open the specified new terminal. */
+
+ tty = open(ttyname, O_RDWR);
+ if (tty == -1)
+ _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);
+}
+
+/* Start an inferior process and returns its pid.
+ ALLARGS is a string containing shell command to run the program.
+ ENV is the environment vector to pass. */
+
+#ifndef SHELL_FILE
+#define SHELL_FILE "/bin/sh"
+#endif
+
+int
+create_inferior (allargs, env)
+ char *allargs;
+ char **env;
+{
+ int pid;
+ char *shell_command;
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ extern int errno;
+
+ /* 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) + strlen (allargs) + 1);
+ strcpy (shell_command, SHELL_COMMAND_CONCAT);
+ strcat (shell_command, allargs);
+#else
+ shell_command = allargs;
+#endif
+
+ /* exec is said to fail if the executable is open. */
+ close_exec_file ();
+
+#if defined(USG) && !defined(HAVE_VFORK)
+ pid = fork ();
+#else
+ pid = vfork ();
+#endif
+
+ if (pid < 0)
+ perror_with_name ("vfork");
+
+ if (pid == 0)
+ {
+#ifdef TIOCGPGRP
+ /* Run inferior in a separate process group. */
+ setpgrp (getpid (), getpid ());
+#endif /* TIOCGPGRP */
+
+#ifdef SET_STACK_LIMIT_HUGE
+ /* Reset the stack limit back to what it was. */
+ {
+ struct rlimit rlim;
+
+ getrlimit (RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = original_stack_limit;
+ setrlimit (RLIMIT_STACK, &rlim);
+ }
+#endif /* SET_STACK_LIMIT_HUGE */
+
+
+ inferior_thisrun_terminal = inferior_io_terminal;
+ if (inferior_io_terminal != 0)
+ new_tty (inferior_io_terminal);
+
+/* It seems that changing the signal handlers for the inferior after
+ a vfork also changes them for the superior. See comments in
+ initialize_signals for how we get the right signal handlers
+ for the inferior. */
+/* Not needed on Sun, at least, and loses there
+ because it clobbers the superior. */
+/*??? signal (SIGQUIT, SIG_DFL);
+ signal (SIGINT, SIG_DFL); */
+
+ call_ptrace (0);
+ execle (SHELL_FILE, "sh", "-c", shell_command, 0, env);
+
+ fprintf (stderr, "Cannot exec %s: %s.\n", SHELL_FILE,
+ errno < sys_nerr ? sys_errlist[errno] : "unknown error");
+ fflush (stderr);
+ _exit (0177);
+ }
+
+#ifdef TIOCGPGRP
+ /* Avoid race with TIOCSPGRP: guarantee that inferior's pgrp exists. */
+ setpgrp (pid, pid);
+#endif /* TIOCGPGRP */
+
+#ifdef CREATE_INFERIOR_HOOK
+ CREATE_INFERIOR_HOOK (pid);
+#endif
+ return pid;
+}
+
+/* Kill the inferior process. Make us have no inferior. */
+
+static void
+kill_command ()
+{
+ if (remote_debugging)
+ {
+ inferior_pid = 0;
+ return;
+ }
+ if (inferior_pid == 0)
+ error ("The program is not being run.");
+ if (!query ("Kill the inferior process? "))
+ error ("Not confirmed.");
+ kill_inferior ();
+}
+
+void
+inferior_died ()
+{
+ inferior_pid = 0;
+ attach_flag = 0;
+ mark_breakpoints_out ();
+ select_frame ((FRAME) 0, -1);
+ reopen_exec_file ();
+ if (have_core_file_p ())
+ set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+ else
+ set_current_frame (0);
+}
+
+#if 0
+/* This function is just for testing, and on some systems (Sony NewsOS
+ 3.2) <sys/user.h> also includes <sys/time.h> which leads to errors
+ (since on this system at least sys/time.h is not protected against
+ multiple inclusion). */
+static void
+try_writing_regs_command ()
+{
+ register int i;
+ register int value;
+ extern int errno;
+
+ if (inferior_pid == 0)
+ error ("There is no inferior process now.");
+
+ /* A Sun 3/50 or 3/60 (at least) running SunOS 4.0.3 will have a
+ kernel panic if we try to write past the end of the user area.
+ Presumably Sun will fix this bug (it has been reported), but it
+ is tacky to crash the system, so at least on SunOS4 we need to
+ stop writing when we hit the end of the user area. */
+ for (i = 0; i < sizeof (struct user); i += 2)
+ {
+ QUIT;
+ errno = 0;
+ value = call_ptrace (3, inferior_pid, i, 0);
+ call_ptrace (6, inferior_pid, i, value);
+ if (errno == 0)
+ {
+ printf (" Succeeded with address 0x%x; value 0x%x (%d).\n",
+ i, value, value);
+ }
+ else if ((i & 0377) == 0)
+ printf (" Failed at 0x%x.\n", i);
+ }
+}
+#endif
+
+void
+_initialize_inflow ()
+{
+ add_com ("term-status", class_obscure, term_status_command,
+ "Print info on inferior's saved terminal status.");
+
+#if 0
+ add_com ("try-writing-regs", class_obscure, try_writing_regs_command,
+ "Try writing all locations in inferior's system block.\n\
+Report which ones can be written.");
+#endif
+
+ add_com ("kill", class_run, kill_command,
+ "Kill execution of program being debugged.");
+
+ inferior_pid = 0;
+
+ ioctl (0, TIOCGETP, &sg_ours);
+ tflags_ours = fcntl (0, F_GETFL, 0);
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+ ioctl (0, TIOCGETC, &tc_ours);
+#endif
+#ifdef TIOCGLTC
+ ioctl (0, TIOCGLTC, &ltc_ours);
+#endif
+#ifdef TIOCLGET
+ ioctl (0, TIOCLGET, &lmode_ours);
+#endif
+
+#ifdef TIOCGPGRP
+ ioctl (0, TIOCGPGRP, &pgrp_ours);
+#endif /* TIOCGPGRP */
+
+ terminal_is_ours = 1;
+}
+
diff --git a/gnu/usr.bin/gdb/infrun.c b/gnu/usr.bin/gdb/infrun.c
new file mode 100644
index 0000000..887a0bb
--- /dev/null
+++ b/gnu/usr.bin/gdb/infrun.c
@@ -0,0 +1,1459 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)infrun.c 6.4 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Start and stop the inferior process, for GDB.
+ Copyright (C) 1986, 1987, 1988, 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. */
+
+/* Notes on the algorithm used in wait_for_inferior to determine if we
+ just did a subroutine call when stepping. We have the following
+ information at that point:
+
+ Current and previous (just before this step) pc.
+ Current and previous sp.
+ Current and previous start of current function.
+
+ If the start's of the functions don't match, then
+
+ a) We did a subroutine call.
+
+ In this case, the pc will be at the beginning of a function.
+
+ b) We did a subroutine return.
+
+ Otherwise.
+
+ c) We did a longjmp.
+
+ If we did a longjump, we were doing "nexti", since a next would
+ have attempted to skip over the assembly language routine in which
+ the longjmp is coded and would have simply been the equivalent of a
+ continue. I consider this ok behaivior. We'd like one of two
+ things to happen if we are doing a nexti through the longjmp()
+ routine: 1) It behaves as a stepi, or 2) It acts like a continue as
+ above. Given that this is a special case, and that anybody who
+ thinks that the concept of sub calls is meaningful in the context
+ of a longjmp, I'll take either one. Let's see what happens.
+
+ Acts like a subroutine return. I can handle that with no problem
+ at all.
+
+ -->So: If the current and previous beginnings of the current
+ function don't match, *and* the pc is at the start of a function,
+ we've done a subroutine call. If the pc is not at the start of a
+ function, we *didn't* do a subroutine call.
+
+ -->If the beginnings of the current and previous function do match,
+ either:
+
+ a) We just did a recursive call.
+
+ In this case, we would be at the very beginning of a
+ function and 1) it will have a prologue (don't jump to
+ before prologue, or 2) (we assume here that it doesn't have
+ a prologue) there will have been a change in the stack
+ pointer over the last instruction. (Ie. it's got to put
+ the saved pc somewhere. The stack is the usual place. In
+ a recursive call a register is only an option if there's a
+ prologue to do something with it. This is even true on
+ register window machines; the prologue sets up the new
+ window. It might not be true on a register window machine
+ where the call instruction moved the register window
+ itself. Hmmm. One would hope that the stack pointer would
+ also change. If it doesn't, somebody send me a note, and
+ I'll work out a more general theory.
+ randy@wheaties.ai.mit.edu). This is true (albeit slipperly
+ so) on all machines I'm aware of:
+
+ m68k: Call changes stack pointer. Regular jumps don't.
+
+ sparc: Recursive calls must have frames and therefor,
+ prologues.
+
+ vax: All calls have frames and hence change the
+ stack pointer.
+
+ b) We did a return from a recursive call. I don't see that we
+ have either the ability or the need to distinguish this
+ from an ordinary jump. The stack frame will be printed
+ when and if the frame pointer changes; if we are in a
+ function without a frame pointer, it's the users own
+ lookout.
+
+ c) We did a jump within a function. We assume that this is
+ true if we didn't do a recursive call.
+
+ d) We are in no-man's land ("I see no symbols here"). We
+ don't worry about this; it will make calls look like simple
+ jumps (and the stack frames will be printed when the frame
+ pointer moves), which is a reasonably non-violent response.
+
+#if 0
+ We skip this; it causes more problems than it's worth.
+#ifdef SUN4_COMPILER_FEATURE
+ We do a special ifdef for the sun 4, forcing it to single step
+ into calls which don't have prologues. This means that we can't
+ nexti over leaf nodes, we can probably next over them (since they
+ won't have debugging symbols, usually), and we can next out of
+ functions returning structures (with a "call .stret4" at the end).
+#endif
+#endif
+*/
+
+
+
+
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "inferior.h"
+#include "wait.h"
+
+#include <signal.h>
+
+/* unistd.h is needed to #define X_OK */
+#ifdef USG
+#include <unistd.h>
+#else
+#include <sys/file.h>
+#endif
+
+#ifdef UMAX_PTRACE
+#include <aouthdr.h>
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#endif /* UMAX_PTRACE */
+
+/* Required by <sys/user.h>. */
+#include <sys/types.h>
+/* Required by <sys/user.h>, at least on system V. */
+#include <sys/dir.h>
+/* Needed by IN_SIGTRAMP on some machines (e.g. vax). */
+#include <sys/param.h>
+/* Needed by IN_SIGTRAMP on some machines (e.g. vax). */
+#include <sys/user.h>
+
+extern char *sys_siglist[];
+extern int errno;
+
+/* 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)
+#define IN_SIGTRAMP(pc, name) \
+ name && !strcmp ("_sigtramp", name)
+#endif
+
+/* Tables of how to react to signals; the user sets them. */
+
+static char signal_stop[NSIG];
+static char signal_print[NSIG];
+static char signal_program[NSIG];
+
+/* 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;
+
+/* This is the sequence of bytes we insert for a breakpoint. */
+
+static char break_insn[] = BREAKPOINT;
+
+/* Nonzero => address for special breakpoint for resuming stepping. */
+
+static CORE_ADDR step_resume_break_address;
+
+/* Original contents of the byte where the special breakpoint is. */
+
+static char step_resume_break_shadow[sizeof break_insn];
+
+/* Nonzero means the special breakpoint is a duplicate
+ so it has not itself been inserted. */
+
+static int step_resume_break_duplicate;
+
+/* Nonzero if we are expecting a trace trap and should proceed from it.
+ 2 means expecting 2 trace traps and should continue both times.
+ That occurs when we tell sh to exec the program: we will get
+ a trap after the exec of sh and a second when the program is exec'd. */
+
+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 trace trap due to attaching to a process. */
+
+int stop_after_attach;
+
+/* Nonzero if pc has been changed by the debugger
+ since the inferior stopped. */
+
+int pc_changed;
+
+/* Nonzero if debugging a remote machine via a serial link or ethernet. */
+
+int remote_debugging;
+
+/* Nonzero if program stopped due to error trying to insert breakpoints. */
+
+static int breakpoints_failed;
+
+/* Nonzero if inferior is in sh before our program got exec'd. */
+
+static int running_in_shell;
+
+/* 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 */
+
+static void insert_step_breakpoint ();
+static void remove_step_breakpoint ();
+static void wait_for_inferior ();
+static void normal_stop ();
+
+
+/* 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;
+ step_resume_break_address = 0;
+ stop_after_trap = 0;
+ stop_after_attach = 0;
+
+ /* Discard any remaining commands left by breakpoint we had stopped at. */
+ clear_breakpoint_commands ();
+}
+
+/* Basic routine for continuing the program in various fashions.
+
+ ADDR is the address to resume at, or -1 for resume where stopped.
+ SIGNAL 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, signal, step)
+ CORE_ADDR addr;
+ int signal;
+ 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 == -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 (!pc_changed && breakpoint_here_p (read_pc ()))
+ oneproc = 1;
+ }
+ else
+ {
+ write_register (PC_REGNUM, addr);
+#ifdef NPC_REGNUM
+ write_register (NPC_REGNUM, addr + 4);
+#endif
+ }
+
+ 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;
+ }
+
+ /* Install inferior's terminal modes. */
+ terminal_inferior ();
+
+ if (signal >= 0)
+ stop_signal = signal;
+ /* If this signal should not be seen by program,
+ give it zero. Used for debugging signals. */
+ else if (stop_signal < NSIG && !signal_program[stop_signal])
+ stop_signal= 0;
+
+ /* Resume inferior. */
+ resume (oneproc || 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 ();
+}
+
+/* Writing the inferior pc as a register calls this function
+ to inform infrun that the pc has been set in the debugger. */
+
+void
+writing_pc (val)
+ CORE_ADDR val;
+{
+ stop_pc = val;
+ pc_changed = 1;
+}
+
+/* Start an inferior process for the first time.
+ Actually it was started by the fork that created it,
+ but it will have stopped one instruction after execing sh.
+ Here we must get it up to actual execution of the real program. */
+
+void
+start_inferior ()
+{
+ /* We will get a trace trap after one instruction.
+ Continue it automatically. Eventually (after shell does an exec)
+ it will get another trace trap. Then insert breakpoints and continue. */
+
+#ifdef START_INFERIOR_TRAPS_EXPECTED
+ trap_expected = START_INFERIOR_TRAPS_EXPECTED;
+#else
+ trap_expected = 2;
+#endif
+
+ running_in_shell = 0; /* Set to 1 at first SIGTRAP, 0 at second. */
+ trap_expected_after_continue = 0;
+ breakpoints_inserted = 0;
+ mark_breakpoints_out ();
+
+ /* Set up the "saved terminal modes" of the inferior
+ based on what modes we are starting it with. */
+ terminal_init_inferior ();
+
+ /* Install inferior's terminal modes. */
+ terminal_inferior ();
+
+ if (remote_debugging)
+ {
+ trap_expected = 0;
+ fetch_inferior_registers();
+ set_current_frame (create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+ stop_frame_address = FRAME_FP (get_current_frame());
+ inferior_pid = 3;
+ if (insert_breakpoints())
+ fatal("Can't insert breakpoints");
+ breakpoints_inserted = 1;
+ proceed(-1, -1, 0);
+ }
+ else
+ {
+ wait_for_inferior ();
+ normal_stop ();
+ }
+}
+
+/* Start or restart remote-debugging of a machine over a serial link. */
+
+void
+restart_remote ()
+{
+ clear_proceed_status ();
+ running_in_shell = 0;
+ trap_expected = 0;
+ stop_after_attach = 1;
+ inferior_pid = 3;
+ wait_for_inferior ();
+ normal_stop();
+}
+
+void
+start_remote ()
+{
+ breakpoints_inserted = 0;
+ mark_breakpoints_out ();
+ restart_remote();
+}
+
+#ifdef ATTACH_DETACH
+
+/* Attach to process PID, then initialize for debugging it
+ and wait for the trace-trap that results from attaching. */
+
+void
+attach_program (pid)
+ int pid;
+{
+ attach (pid);
+ inferior_pid = pid;
+
+ mark_breakpoints_out ();
+ terminal_init_inferior ();
+ clear_proceed_status ();
+ stop_after_attach = 1;
+ /*proceed (-1, 0, -2);*/
+ terminal_inferior ();
+ wait_for_inferior ();
+ normal_stop ();
+}
+#endif /* ATTACH_DETACH */
+
+/* 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. */
+
+static void
+wait_for_inferior ()
+{
+ register int pid;
+ WAITTYPE w;
+ CORE_ADDR pc;
+ int tem;
+ int another_trap;
+ int random_signal;
+ CORE_ADDR stop_sp, prev_sp;
+ CORE_ADDR prev_func_start, stop_func_start;
+ char *prev_func_name, *stop_func_name;
+ CORE_ADDR prologue_pc;
+ int stop_step_resume_break;
+ CORE_ADDR step_resume_break_sp;
+ int newmisc;
+ int newfun_pc;
+ struct symtab_and_line sal;
+ int prev_pc;
+ extern CORE_ADDR text_end;
+ int remove_breakpoints_on_following_step = 0;
+
+ prev_pc = read_pc ();
+ (void) find_pc_partial_function (prev_pc, &prev_func_name,
+ &prev_func_start);
+ prev_func_start += FUNCTION_START_OFFSET;
+ prev_sp = read_register (SP_REGNUM);
+
+ while (1)
+ {
+ /* Clean up saved state that will become invalid. */
+ pc_changed = 0;
+ flush_cached_frames ();
+
+ if (remote_debugging)
+ remote_wait (&w);
+ else
+ {
+ pid = wait (&w);
+ if (pid != inferior_pid)
+ continue;
+ }
+
+ /* See if the process still exists; clean up if it doesn't. */
+ if (WIFEXITED (w))
+ {
+ terminal_ours_for_output ();
+ if (WEXITSTATUS (w))
+ printf ("\nProgram exited with code 0%o.\n", WEXITSTATUS (w));
+ else
+ printf ("\nProgram exited normally.\n");
+ fflush (stdout);
+ inferior_died ();
+#ifdef NO_SINGLE_STEP
+ one_stepped = 0;
+#endif
+ stop_print_frame = 0;
+ break;
+ }
+ else if (!WIFSTOPPED (w))
+ {
+ kill_inferior ();
+ stop_print_frame = 0;
+ stop_signal = WTERMSIG (w);
+ terminal_ours_for_output ();
+ printf ("\nProgram terminated with signal %d, %s\n",
+ stop_signal,
+ stop_signal < NSIG
+ ? sys_siglist[stop_signal]
+ : "(undocumented)");
+ printf ("The inferior process no longer exists.\n");
+ fflush (stdout);
+#ifdef NO_SINGLE_STEP
+ one_stepped = 0;
+#endif
+ break;
+ }
+
+#ifdef NO_SINGLE_STEP
+ if (one_stepped)
+ single_step (0); /* This actually cleans up the ss */
+#endif /* NO_SINGLE_STEP */
+
+ fetch_inferior_registers ();
+ stop_pc = read_pc ();
+ set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+ read_pc ()));
+
+ stop_frame_address = FRAME_FP (get_current_frame ());
+ stop_sp = read_register (SP_REGNUM);
+ 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. */
+ (void) find_pc_partial_function (stop_pc, &stop_func_name,
+ &stop_func_start);
+ stop_func_start += FUNCTION_START_OFFSET;
+ another_trap = 0;
+ stop_breakpoint = 0;
+ stop_step = 0;
+ stop_stack_dummy = 0;
+ stop_print_frame = 1;
+ stop_step_resume_break = 0;
+ 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. */
+
+ stop_signal = WSTOPSIG (w);
+
+ /* 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 == SIGTRAP
+ || (breakpoints_inserted &&
+ (stop_signal == SIGILL
+ || stop_signal == SIGEMT))
+ || stop_after_attach)
+ {
+ if (stop_signal == SIGTRAP && stop_after_trap)
+ {
+ stop_print_frame = 0;
+ break;
+ }
+ if (stop_after_attach)
+ break;
+ /* Don't even think about breakpoints
+ if still running the shell that will exec the program
+ or if just proceeded over a breakpoint. */
+ if (stop_signal == SIGTRAP && trap_expected)
+ stop_breakpoint = 0;
+ else
+ {
+ /* See if there is a breakpoint at the current PC. */
+#if DECR_PC_AFTER_BREAK
+ /* Notice the case of stepping through a jump
+ that leads 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. */
+ if (!(prev_pc != stop_pc - DECR_PC_AFTER_BREAK
+ && step_range_end && !step_resume_break_address))
+#endif /* DECR_PC_AFTER_BREAK not zero */
+ {
+ /* See if we stopped at the special breakpoint for
+ stepping over a subroutine call. */
+ if (stop_pc - DECR_PC_AFTER_BREAK
+ == step_resume_break_address)
+ {
+ stop_step_resume_break = 1;
+ if (DECR_PC_AFTER_BREAK)
+ {
+ stop_pc -= DECR_PC_AFTER_BREAK;
+ write_register (PC_REGNUM, stop_pc);
+ pc_changed = 0;
+ }
+ }
+ else
+ {
+ stop_breakpoint =
+ breakpoint_stop_status (stop_pc, stop_frame_address);
+ /* Following in case break condition called a
+ function. */
+ stop_print_frame = 1;
+ if (stop_breakpoint && DECR_PC_AFTER_BREAK)
+ {
+ stop_pc -= DECR_PC_AFTER_BREAK;
+ write_register (PC_REGNUM, stop_pc);
+#ifdef NPC_REGNUM
+ write_register (NPC_REGNUM, stop_pc + 4);
+#endif
+ pc_changed = 0;
+ }
+ }
+ }
+ }
+
+ if (stop_signal == SIGTRAP)
+ random_signal
+ = !(stop_breakpoint || trap_expected
+ || stop_step_resume_break
+#ifndef CANNOT_EXECUTE_STACK
+ || (stop_sp INNER_THAN stop_pc
+ && stop_pc INNER_THAN stop_frame_address)
+#else
+ || stop_pc == text_end - 2
+#endif
+ || (step_range_end && !step_resume_break_address));
+ else
+ {
+ random_signal
+ = !(stop_breakpoint
+ || stop_step_resume_break
+#ifdef sony_news
+ || (stop_sp INNER_THAN stop_pc
+ && stop_pc INNER_THAN stop_frame_address)
+#endif
+
+ );
+ if (!random_signal)
+ stop_signal = SIGTRAP;
+ }
+ }
+ else
+ random_signal = 1;
+
+ /* For the program's own signals, act according to
+ the signal handling tables. */
+
+ if (random_signal
+ && !(running_in_shell && stop_signal == SIGSEGV))
+ {
+ /* Signal not for debugging purposes. */
+ int printed = 0;
+
+ stopped_by_random_signal = 1;
+
+ if (stop_signal >= NSIG
+ || signal_print[stop_signal])
+ {
+ printed = 1;
+ terminal_ours_for_output ();
+ printf ("\nProgram received signal %d, %s\n",
+ stop_signal,
+ stop_signal < NSIG
+ ? sys_siglist[stop_signal]
+ : "(undocumented)");
+ fflush (stdout);
+ }
+ if (stop_signal >= NSIG
+ || signal_stop[stop_signal])
+ break;
+ /* If not going to stop, give terminal back
+ if we took it away. */
+ else if (printed)
+ terminal_inferior ();
+ }
+
+ /* Handle cases caused by hitting a breakpoint. */
+
+ if (!random_signal
+ && (stop_breakpoint || stop_step_resume_break))
+ {
+ /* Does a breakpoint want us to stop? */
+ if (stop_breakpoint && stop_breakpoint != -1
+ && stop_breakpoint != -0x1000001)
+ {
+ /* 0x1000000 is set in stop_breakpoint as returned by
+ breakpoint_stop_status to indicate a silent
+ breakpoint. */
+ if ((stop_breakpoint > 0 ? stop_breakpoint :
+ -stop_breakpoint)
+ & 0x1000000)
+ {
+ stop_print_frame = 0;
+ if (stop_breakpoint > 0)
+ stop_breakpoint -= 0x1000000;
+ else
+ stop_breakpoint += 0x1000000;
+ }
+ break;
+ }
+ /* But if we have hit the step-resumption breakpoint,
+ remove it. It has done its job getting us here.
+ The sp test is to make sure that we don't get hung
+ up in recursive calls in functions without frame
+ pointers. If the stack pointer isn't outside of
+ where the breakpoint was set (within a routine to be
+ stepped over), we're in the middle of a recursive
+ call. Not true for reg window machines (sparc)
+ because the must change frames to call things and
+ the stack pointer doesn't have to change if it
+ the bp was set in a routine without a frame (pc can
+ be stored in some other window).
+
+ The removal of the sp test is to allow calls to
+ alloca. Nasty things were happening. Oh, well,
+ gdb can only handle one level deep of lack of
+ frame pointer. */
+ if (stop_step_resume_break
+ && (step_frame_address == 0
+ || (stop_frame_address == step_frame_address)))
+ {
+ remove_step_breakpoint ();
+ step_resume_break_address = 0;
+ }
+ /* Otherwise, must remove breakpoints and single-step
+ to get us past the one we hit. */
+ else
+ {
+ remove_breakpoints ();
+ remove_step_breakpoint ();
+ breakpoints_inserted = 0;
+ another_trap = 1;
+ }
+
+ /* 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. */
+ }
+
+ /* If this is the breakpoint at the end of a stack dummy,
+ just stop silently. */
+#ifndef CANNOT_EXECUTE_STACK
+ if (stop_sp INNER_THAN stop_pc
+ && stop_pc INNER_THAN stop_frame_address)
+#else
+ if (stop_pc == text_end - 2)
+#endif
+ {
+ stop_print_frame = 0;
+ stop_stack_dummy = 1;
+#ifdef HP_OS_BUG
+ trap_expected_after_continue = 1;
+#endif
+ break;
+ }
+
+ if (step_resume_break_address)
+ /* Having a step-resume breakpoint overrides anything
+ else having to do with stepping commands until
+ that breakpoint is reached. */
+ ;
+ /* If stepping through a line, keep going if still within it. */
+ else if (!random_signal
+ && step_range_end
+ && 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)))
+ {
+ /* Don't step through the return from a function
+ unless that is the first instruction stepped through. */
+ if (ABOUT_TO_RETURN (stop_pc))
+ {
+ stop_step = 1;
+ break;
+ }
+ }
+
+ /* We stepped out of the stepping range. See if that was due
+ to a subroutine call that we should proceed to the end of. */
+ else if (!random_signal && step_range_end)
+ {
+ if (stop_func_start)
+ {
+ prologue_pc = stop_func_start;
+ SKIP_PROLOGUE (prologue_pc);
+ }
+
+ /* Did we just take a signal? */
+ if (IN_SIGTRAMP (stop_pc, stop_func_name)
+ && !IN_SIGTRAMP (prev_pc, prev_func_name))
+ {
+ /* This code is needed at least in the following case:
+ The user types "next" and then a signal arrives (before
+ the "next" is done). */
+ /* We've just taken a signal; go until we are back to
+ the point where we took it and one more. */
+ step_resume_break_address = prev_pc;
+ step_resume_break_duplicate =
+ breakpoint_here_p (step_resume_break_address);
+ step_resume_break_sp = stop_sp;
+ if (breakpoints_inserted)
+ insert_step_breakpoint ();
+ /* Make sure that the stepping range gets us past
+ that instruction. */
+ if (step_range_end == 1)
+ step_range_end = (step_range_start = prev_pc) + 1;
+ remove_breakpoints_on_following_step = 1;
+ }
+
+ /* ==> See comments at top of file on this algorithm. <==*/
+
+ else if (stop_pc == stop_func_start
+ && (stop_func_start != prev_func_start
+ || prologue_pc != stop_func_start
+ || stop_sp != prev_sp))
+ {
+ /* It's a subroutine call */
+ if (step_over_calls > 0
+ || (step_over_calls && find_pc_function (stop_pc) == 0))
+ {
+ /* A subroutine call has happened. */
+ /* Set a special breakpoint after the return */
+ step_resume_break_address =
+ SAVED_PC_AFTER_CALL (get_current_frame ());
+ step_resume_break_duplicate
+ = breakpoint_here_p (step_resume_break_address);
+ step_resume_break_sp = stop_sp;
+ if (breakpoints_inserted)
+ insert_step_breakpoint ();
+ }
+ /* Subroutine call with source code we should not step over.
+ Do step to the first line of code in it. */
+ else if (step_over_calls)
+ {
+ 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.
+ 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)
+ 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. */
+ {
+ step_resume_break_address = stop_func_start;
+ step_resume_break_sp = stop_sp;
+
+ step_resume_break_duplicate
+ = breakpoint_here_p (step_resume_break_address);
+ if (breakpoints_inserted)
+ insert_step_breakpoint ();
+ /* 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_frame_address = 0;
+ /* And make sure stepping stops right away then. */
+ step_range_end = step_range_start;
+ }
+ }
+ else
+ {
+ /* We get here only if step_over_calls is 0 and we
+ just stepped into a subroutine. I presume
+ that step_over_calls is only 0 when we're
+ supposed to be stepping at the assembly
+ language level.*/
+ stop_step = 1;
+ break;
+ }
+ }
+ /* No subroutince call; stop now. */
+ else
+ {
+ stop_step = 1;
+ break;
+ }
+ }
+
+ /* 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;
+
+ /* If we did not do break;, it means we should keep
+ running the inferior and not return to debugger. */
+
+ /* If trap_expected is 2, it means continue once more
+ and insert breakpoints at the next trap.
+ If trap_expected is 1 and the signal was SIGSEGV, it means
+ the shell is doing some memory allocation--just resume it
+ with SIGSEGV.
+ Otherwise insert breakpoints now, and possibly single step. */
+
+ if (trap_expected > 1)
+ {
+ trap_expected--;
+ running_in_shell = 1;
+ resume (0, 0);
+ }
+ else if (running_in_shell && stop_signal == SIGSEGV)
+ {
+ resume (0, SIGSEGV);
+ }
+ else if (trap_expected && stop_signal != SIGTRAP)
+ {
+ /* We took a signal which we are supposed to pass through to
+ the inferior and we haven't yet gotten our trap. Simply
+ continue. */
+ resume ((step_range_end && !step_resume_break_address)
+ || trap_expected,
+ stop_signal);
+ }
+ else
+ {
+ /* Here, we are not awaiting another exec to get
+ the program we really want to debug.
+ Insert breakpoints now, unless we are trying
+ to one-proceed past a breakpoint. */
+ running_in_shell = 0;
+ /* If we've just finished a special step resume and we don't
+ want to hit a breakpoint, pull em out. */
+ if (!step_resume_break_address &&
+ remove_breakpoints_on_following_step)
+ {
+ remove_breakpoints_on_following_step = 0;
+ remove_breakpoints ();
+ breakpoints_inserted = 0;
+ }
+ else if (!breakpoints_inserted && !another_trap)
+ {
+ insert_step_breakpoint ();
+ breakpoints_failed = insert_breakpoints ();
+ if (breakpoints_failed)
+ break;
+ breakpoints_inserted = 1;
+ }
+
+ trap_expected = another_trap;
+
+ if (stop_signal == SIGTRAP)
+ stop_signal = 0;
+
+ resume ((step_range_end && !step_resume_break_address)
+ || trap_expected,
+ stop_signal);
+ }
+ }
+}
+
+/* Here to return control to GDB when the inferior stops for real.
+ Print appropriate messages, remove breakpoints, give terminal our modes.
+
+ RUNNING_IN_SHELL nonzero means the shell got a signal before
+ exec'ing the program we wanted to run.
+ 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. */
+
+static 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 (inferior_pid)
+ (get_current_frame ())->pc = read_pc ();
+
+ if (breakpoints_failed)
+ {
+ terminal_ours_for_output ();
+ print_sys_errmsg ("ptrace", breakpoints_failed);
+ printf ("Stopped; cannot insert breakpoints.\n\
+The same program may be running in another process.\n");
+ }
+
+ if (inferior_pid)
+ remove_step_breakpoint ();
+
+ if (inferior_pid && breakpoints_inserted)
+ if (remove_breakpoints ())
+ {
+ terminal_ours_for_output ();
+ printf ("Cannot remove breakpoints because program is no longer writable.\n\
+It must 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_breakpoint);
+
+ /* 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)
+ return;
+
+ terminal_ours ();
+
+ if (running_in_shell)
+ {
+ if (stop_signal == SIGSEGV)
+ {
+ char *exec_file = (char *) get_exec_file (1);
+
+ if (access (exec_file, X_OK) != 0)
+ printf ("The file \"%s\" is not executable.\n", exec_file);
+ else
+ /* I don't think we should ever get here.
+ wait_for_inferior now ignores SIGSEGV's which happen in
+ the shell (since the Bourne shell (/bin/sh) has some
+ rather, er, uh, *unorthodox* memory management
+ involving catching SIGSEGV). */
+ printf ("\
+You have just encountered a bug in \"sh\". GDB starts your program\n\
+by running \"sh\" with a command to exec your program.\n\
+This is so that \"sh\" will process wildcards and I/O redirection.\n\
+This time, \"sh\" crashed.\n\
+\n\
+One known bug in \"sh\" bites when the environment takes up a lot of space.\n\
+Try \"info env\" to see the environment; then use \"delete env\" to kill\n\
+some variables whose values are large; then do \"run\" again.\n\
+\n\
+If that works, you might want to put those \"delete env\" commands\n\
+into a \".gdbinit\" file in this directory so they will happen every time.\n");
+ }
+ /* Don't confuse user with his program's symbols on sh's data. */
+ stop_print_frame = 0;
+ }
+
+ if (inferior_pid == 0)
+ return;
+
+ /* Select innermost stack frame except on return from a stack dummy routine,
+ or if the program has exited. */
+ if (!stop_stack_dummy)
+ {
+ select_frame (get_current_frame (), 0);
+
+ if (stop_print_frame)
+ {
+ if (stop_breakpoint > 0)
+ printf ("\nBpt %d, ", stop_breakpoint);
+ print_sel_frame (stop_step
+ && step_frame_address == stop_frame_address
+ && step_start_function == find_pc_function (stop_pc));
+ /* Display the auto-display expressions. */
+ do_displays ();
+ }
+ }
+
+ 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. */
+#ifndef NEW_CALL_FUNCTION
+ POP_FRAME;
+#endif
+ select_frame (get_current_frame (), 0);
+ }
+}
+
+static void
+insert_step_breakpoint ()
+{
+ if (step_resume_break_address && !step_resume_break_duplicate)
+ {
+ read_memory (step_resume_break_address,
+ step_resume_break_shadow, sizeof break_insn);
+ write_memory (step_resume_break_address,
+ break_insn, sizeof break_insn);
+ }
+}
+
+static void
+remove_step_breakpoint ()
+{
+ if (step_resume_break_address && !step_resume_break_duplicate)
+ write_memory (step_resume_break_address, step_resume_break_shadow,
+ sizeof break_insn);
+}
+
+/* Specify how various signals in the inferior should be handled. */
+
+static void
+handle_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ register char *p = args;
+ int signum = 0;
+ register int digits, wordlen;
+
+ if (!args)
+ error_no_arg ("signal to handle");
+
+ while (*p)
+ {
+ /* Find the end of the next word in the args. */
+ for (wordlen = 0; p[wordlen] && p[wordlen] != ' ' && p[wordlen] != '\t';
+ wordlen++);
+ for (digits = 0; p[digits] >= '0' && p[digits] <= '9'; digits++);
+
+ /* If it is all digits, it is signal number to operate on. */
+ if (digits == wordlen)
+ {
+ signum = atoi (p);
+ if (signum <= 0 || signum >= NSIG)
+ {
+ p[wordlen] = '\0';
+ error ("Invalid signal %s given as argument to \"handle\".", p);
+ }
+ if (signum == SIGTRAP || signum == SIGINT)
+ {
+ if (!query ("Signal %d is used by the debugger.\nAre you sure you want to change it? ", signum))
+ error ("Not confirmed.");
+ }
+ }
+ else if (signum == 0)
+ error ("First argument is not a signal number.");
+
+ /* Else, if already got a signal number, look for flag words
+ saying what to do for it. */
+ else if (!strncmp (p, "stop", wordlen))
+ {
+ signal_stop[signum] = 1;
+ signal_print[signum] = 1;
+ }
+ else if (wordlen >= 2 && !strncmp (p, "print", wordlen))
+ signal_print[signum] = 1;
+ else if (wordlen >= 2 && !strncmp (p, "pass", wordlen))
+ signal_program[signum] = 1;
+ else if (!strncmp (p, "ignore", wordlen))
+ signal_program[signum] = 0;
+ else if (wordlen >= 3 && !strncmp (p, "nostop", wordlen))
+ signal_stop[signum] = 0;
+ else if (wordlen >= 4 && !strncmp (p, "noprint", wordlen))
+ {
+ signal_print[signum] = 0;
+ signal_stop[signum] = 0;
+ }
+ else if (wordlen >= 4 && !strncmp (p, "nopass", wordlen))
+ signal_program[signum] = 0;
+ else if (wordlen >= 3 && !strncmp (p, "noignore", wordlen))
+ signal_program[signum] = 1;
+ /* Not a number and not a recognized flag word => complain. */
+ else
+ {
+ p[wordlen] = 0;
+ error ("Unrecognized flag word: \"%s\".", p);
+ }
+
+ /* Find start of next word. */
+ p += wordlen;
+ while (*p == ' ' || *p == '\t') p++;
+ }
+
+ if (from_tty)
+ {
+ /* Show the results. */
+ printf ("Number\tStop\tPrint\tPass to program\tDescription\n");
+ printf ("%d\t", signum);
+ printf ("%s\t", signal_stop[signum] ? "Yes" : "No");
+ printf ("%s\t", signal_print[signum] ? "Yes" : "No");
+ printf ("%s\t\t", signal_program[signum] ? "Yes" : "No");
+ printf ("%s\n", sys_siglist[signum]);
+ }
+}
+
+/* Print current contents of the tables set by the handle command. */
+
+static void
+signals_info (signum_exp)
+ char *signum_exp;
+{
+ register int i;
+ printf_filtered ("Number\tStop\tPrint\tPass to program\tDescription\n");
+
+ if (signum_exp)
+ {
+ i = parse_and_eval_address (signum_exp);
+ if (i >= NSIG || i < 0)
+ error ("Signal number out of bounds.");
+ printf_filtered ("%d\t", i);
+ printf_filtered ("%s\t", signal_stop[i] ? "Yes" : "No");
+ printf_filtered ("%s\t", signal_print[i] ? "Yes" : "No");
+ printf_filtered ("%s\t\t", signal_program[i] ? "Yes" : "No");
+ printf_filtered ("%s\n", sys_siglist[i]);
+ return;
+ }
+
+ printf_filtered ("\n");
+ for (i = 0; i < NSIG; i++)
+ {
+ QUIT;
+
+ printf_filtered ("%d\t", i);
+ printf_filtered ("%s\t", signal_stop[i] ? "Yes" : "No");
+ printf_filtered ("%s\t", signal_print[i] ? "Yes" : "No");
+ printf_filtered ("%s\t\t", signal_program[i] ? "Yes" : "No");
+ printf_filtered ("%s\n", sys_siglist[i]);
+ }
+
+ 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). */
+
+struct command_line *get_breakpoint_commands ();
+
+void
+save_inferior_status (inf_status, restore_stack_info)
+ struct inferior_status *inf_status;
+ int restore_stack_info;
+{
+ inf_status->pc_changed = pc_changed;
+ inf_status->stop_signal = stop_signal;
+ inf_status->stop_pc = stop_pc;
+ inf_status->stop_frame_address = stop_frame_address;
+ inf_status->stop_breakpoint = stop_breakpoint;
+ 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->step_resume_break_address = step_resume_break_address;
+ inf_status->stop_after_trap = stop_after_trap;
+ inf_status->stop_after_attach = stop_after_attach;
+ inf_status->breakpoint_commands = get_breakpoint_commands ();
+ inf_status->restore_stack_info = restore_stack_info;
+
+ read_register_bytes(0, inf_status->register_context, REGISTER_BYTES);
+ record_selected_frame (&(inf_status->selected_frame_address),
+ &(inf_status->selected_level));
+ return;
+}
+
+void
+restore_inferior_status (inf_status)
+ struct inferior_status *inf_status;
+{
+ FRAME fid;
+ int level = inf_status->selected_level;
+
+ pc_changed = inf_status->pc_changed;
+ stop_signal = inf_status->stop_signal;
+ stop_pc = inf_status->stop_pc;
+ stop_frame_address = inf_status->stop_frame_address;
+ stop_breakpoint = inf_status->stop_breakpoint;
+ 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;
+ step_resume_break_address = inf_status->step_resume_break_address;
+ stop_after_trap = inf_status->stop_after_trap;
+ stop_after_attach = inf_status->stop_after_attach;
+ set_breakpoint_commands (inf_status->breakpoint_commands);
+
+ write_register_bytes(0, inf_status->register_context, REGISTER_BYTES);
+
+ /* The inferior can be gone if the user types "print exit(0)"
+ (and perhaps other times). */
+ if (have_inferior_p() && inf_status->restore_stack_info)
+ {
+ flush_cached_frames();
+ set_current_frame(create_new_frame(read_register (FP_REGNUM),
+ read_pc()));
+
+ fid = find_relative_frame (get_current_frame (), &level);
+
+ if (fid == 0 ||
+ FRAME_FP (fid) != inf_status->selected_frame_address ||
+ level != 0)
+ {
+ /* I'm not sure this error message is a good idea. I have
+ only seen it occur after "Can't continue previously
+ requested operation" (we get called from do_cleanups), in
+ which case it just adds insult to injury (one confusing
+ error message after another. Besides which, does the
+ user really care if we can't restore the previously
+ selected frame? */
+ fprintf (stderr, "Unable to restore previously selected frame.\n");
+ select_frame (get_current_frame (), 0);
+ return;
+ }
+
+ select_frame (fid, inf_status->selected_level);
+ }
+ return;
+}
+
+
+void
+_initialize_infrun ()
+{
+ register int i;
+
+ 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_com ("handle", class_run, handle_command,
+ "Specify how to handle a signal.\n\
+Args are signal number followed by flags.\n\
+Flags allowed are \"stop\", \"print\", \"pass\",\n\
+ \"nostop\", \"noprint\" or \"nopass\".\n\
+Print means print a message if this signal happens.\n\
+Stop means reenter debugger if this signal happens (implies print).\n\
+Pass means let program see this signal; otherwise program doesn't know.\n\
+Pass and Stop may be combined.");
+
+ for (i = 0; i < NSIG; 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[SIGTRAP] = 0;
+ signal_program[SIGINT] = 0;
+
+ /* Signals that are not errors should not normally enter the debugger. */
+#ifdef SIGALRM
+ signal_stop[SIGALRM] = 0;
+ signal_print[SIGALRM] = 0;
+#endif /* SIGALRM */
+#ifdef SIGVTALRM
+ signal_stop[SIGVTALRM] = 0;
+ signal_print[SIGVTALRM] = 0;
+#endif /* SIGVTALRM */
+#ifdef SIGPROF
+ signal_stop[SIGPROF] = 0;
+ signal_print[SIGPROF] = 0;
+#endif /* SIGPROF */
+#ifdef SIGCHLD
+ signal_stop[SIGCHLD] = 0;
+ signal_print[SIGCHLD] = 0;
+#endif /* SIGCHLD */
+#ifdef SIGCLD
+ signal_stop[SIGCLD] = 0;
+ signal_print[SIGCLD] = 0;
+#endif /* SIGCLD */
+#ifdef SIGIO
+ signal_stop[SIGIO] = 0;
+ signal_print[SIGIO] = 0;
+#endif /* SIGIO */
+#ifdef SIGURG
+ signal_stop[SIGURG] = 0;
+ signal_print[SIGURG] = 0;
+#endif /* SIGURG */
+}
+
diff --git a/gnu/usr.bin/gdb/kgdb_proto.h b/gnu/usr.bin/gdb/kgdb_proto.h
new file mode 100644
index 0000000..8bbd5be
--- /dev/null
+++ b/gnu/usr.bin/gdb/kgdb_proto.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Steven McCanne of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)kgdb_proto.h 6.3 (Berkeley) 5/8/91
+ *
+ *
+ * $Header: /home/cvs/386BSD/src/usr.bin/gdb/kgdb_proto.h,v 1.1.1.1 1993/06/12 14:52:25 rgrimes Exp $ (LBL)
+ */
+
+/*
+ * Message types.
+ */
+#define KGDB_MEM_R 0x01
+#define KGDB_MEM_W 0x02
+#define KGDB_REG_R 0x03
+#define KGDB_REG_W 0x04
+#define KGDB_CONT 0x05
+#define KGDB_STEP 0x06
+#define KGDB_KILL 0x07
+#define KGDB_SIGNAL 0x08
+#define KGDB_EXEC 0x09
+
+#define KGDB_CMD(x) ((x) & 0x0f)
+
+/*
+ * Message flags.
+ */
+#define KGDB_ACK 0x80
+#define KGDB_DELTA 0x40
+#define KGDB_MORE 0x20
+#define KGDB_SEQ 0x10
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..8387812
--- /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 \
+ 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..573fa0a
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/README.FreeBSD
@@ -0,0 +1,7 @@
+This is a greatly pared down libiberty directory. Only what's required to build
+gdb-4.12 on FreeBSD was kept.
+
+This is temporary. In FreeBSD 2.0 a fully ported libiberty will likely appear
+as a system library for use by all the build tools.
+
+paul@freefall.cdrom.com
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..fed46e7
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/argv.c
@@ -0,0 +1,332 @@
+/* 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"
+
+/* 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 (*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",
+ "",
+ 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..f61a308
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/basename.c
@@ -0,0 +1,56 @@
+/* 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.
+*/
+
+
+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..61f7d97
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/concat.c
@@ -0,0 +1,118 @@
+/* Concatenate variable number of strings.
+ Copyright (C) 1991 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 <varargs.h>
+
+#define NULLP (char *)0
+
+extern char *xmalloc ();
+
+/* VARARGS */
+char *
+concat (va_alist)
+ va_dcl
+{
+ register int length = 0;
+ register char *newstr;
+ register char *end;
+ register char *arg;
+ va_list args;
+
+ /* First compute the size of the result and get sufficient memory. */
+
+ va_start (args);
+ while ((arg = va_arg (args, 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)
+ {
+ va_start (args);
+ end = newstr;
+ while ((arg = va_arg (args, char *)) != NULLP)
+ {
+ while (*arg)
+ {
+ *end++ = *arg++;
+ }
+ }
+ *end = '\000';
+ va_end (args);
+ }
+
+ return (newstr);
+}
+
+#ifdef MAIN
+
+/* Simple little test driver. */
+
+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));
+}
+
+#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..2ad0e97
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/cplus-dem.c
@@ -0,0 +1,2669 @@
+/* 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>
+
+extern char *xmalloc PARAMS((long));
+extern char *xrealloc PARAMS((PTR, long));
+extern char *strstr PARAMS ((const char *, const char *));
+extern void free PARAMS((PTR));
+
+/* 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) */
+ {"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);
+}
+
+/* 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 *name, int options)
+
+ If NAME 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
+ TYPE. */
+
+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);
+ success = demangle_template (work, mangled, &tname, &trawname);
+ 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);
+ 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)
+ {
+ 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 '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': /* repetition of following */
+ 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:
+ abort ();
+ }
+ }
+ 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;
+ }
+ 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 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)
+ {
+ 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;
+ 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 (strncmp(*mangled, "_GLOBAL_$D$", 11) == 0)
+ {
+ /* it's a GNU global destructor to be executed at program exit */
+ (*mangled) += 11;
+ work->destructor = 2;
+ }
+ else if (strncmp(*mangled, "_GLOBAL_$I$", 11) == 0)
+ {
+ /* it's a GNU global constructor to be executed at program initial */
+ (*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]. */
+ 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 (*(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)
+ _3foo$varname (static data member)
+ _Q22rs2tu$vw (static data member)
+ __t6vector1Zii (constructor with template)
+ */
+
+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] == '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. */
+ (*mangled) += 4;
+ while (**mangled != '\0')
+ {
+ if (isdigit(*mangled[0]))
+ {
+ n = consume_count(mangled);
+ }
+ else
+ {
+ n = strcspn (*mangled, cplus_markers);
+ }
+ string_appendn (declp, *mangled, n);
+ (*mangled) += n;
+
+ if (**mangled != '\0')
+ {
+ string_append (declp, "::");
+ (*mangled)++;
+ }
+ }
+ 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
+ {
+ 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':
+ (*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 '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$", 5) == 0)
+ {
+ /* 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. 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);
+ }
+}
+
+char *
+xmalloc (size)
+ long size;
+{
+ char * newmem;
+
+ if ((newmem = (char *) malloc ((int) size)) == NULL)
+ {
+ fprintf (stderr, "\nCan't allocate %u bytes\n", size);
+ exit (1);
+ }
+ return (newmem);
+}
+
+char *
+xrealloc (oldmem, size)
+ PTR oldmem;
+ long size;
+{
+ char * newmem;
+
+ if ((newmem = (char *) realloc ((char *) oldmem, (int) size)) == NULL)
+ {
+ fprintf (stderr, "\nCan't reallocate %u bytes\n", size);
+ exit (1);
+ }
+ return (newmem);
+}
+
+#include "getopt.h"
+
+static char *program_name;
+extern char *program_version;
+
+static void
+usage (stream, status)
+ FILE *stream;
+ int status;
+{
+ fprintf (stream, "\
+Usage: %s [-_] [-s {gnu,lucid,arm}] [--strip-underscores]\n\
+ [--format={gnu,lucid,arm}] [--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'},
+ {"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];
+ strip_underscore = prepends_underscore;
+
+ while ((c = getopt_long (argc, argv, "_s:", long_options, (int *) 0)) != EOF)
+ {
+ switch (c)
+ {
+ case '?':
+ usage (stderr, 1);
+ break;
+ case 'h':
+ usage (stdout, 0);
+ 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..0a6de2a
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/fdmatch.c
@@ -0,0 +1,71 @@
+/* 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 <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..c7a8b03
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/getopt.c
@@ -0,0 +1,750 @@
+/* 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 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
+#include "config.h"
+#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__
+/* 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.
+ (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 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/gdb/libiberty/getopt1.c b/gnu/usr.bin/gdb/libiberty/getopt1.c
new file mode 100644
index 0000000..6806da5
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/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 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
+#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/gdb/libiberty/ieee-float.c b/gnu/usr.bin/gdb/libiberty/ieee-float.c
new file mode 100644
index 0000000..b50eb85
--- /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..4297bbb
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/obstack.c
@@ -0,0 +1,460 @@
+/* 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 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. */
+
+#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. */
+
+#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..545b12e
--- /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..28f0746
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/spaces.c
@@ -0,0 +1,67 @@
+/* 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
+
+*/
+
+
+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);
+ for (t = buf + count ; t != buf ; )
+ {
+ *--t = ' ';
+ }
+ maxsize = count;
+ buf[count] = '\0';
+ }
+ return (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..f377311
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/strerror.c
@@ -0,0 +1,811 @@
+/* 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 "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__ */
+#ifndef const
+#define const
+#endif
+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> */
+ char *name; /* The equivalent symbolic value */
+ char *msg; /* Short message about this value */
+};
+
+static const struct error_info error_table[] =
+{
+#if defined (EPERM)
+ {EPERM, "EPERM", "Not owner"},
+#endif
+#if defined (ENOENT)
+ {ENOENT, "ENOENT", "No such file or directory"},
+#endif
+#if defined (ESRCH)
+ {ESRCH, "ESRCH", "No such process"},
+#endif
+#if defined (EINTR)
+ {EINTR, "EINTR", "Interrupted system call"},
+#endif
+#if defined (EIO)
+ {EIO, "EIO", "I/O error"},
+#endif
+#if defined (ENXIO)
+ {ENXIO, "ENXIO", "No such device or address"},
+#endif
+#if defined (E2BIG)
+ {E2BIG, "E2BIG", "Arg list too long"},
+#endif
+#if defined (ENOEXEC)
+ {ENOEXEC, "ENOEXEC", "Exec format error"},
+#endif
+#if defined (EBADF)
+ {EBADF, "EBADF", "Bad file number"},
+#endif
+#if defined (ECHILD)
+ {ECHILD, "ECHILD", "No child processes"},
+#endif
+#if defined (EWOULDBLOCK) /* Put before EAGAIN, sometimes aliased */
+ {EWOULDBLOCK, "EWOULDBLOCK", "Operation would block"},
+#endif
+#if defined (EAGAIN)
+ {EAGAIN, "EAGAIN", "No more processes"},
+#endif
+#if defined (ENOMEM)
+ {ENOMEM, "ENOMEM", "Not enough space"},
+#endif
+#if defined (EACCES)
+ {EACCES, "EACCES", "Permission denied"},
+#endif
+#if defined (EFAULT)
+ {EFAULT, "EFAULT", "Bad address"},
+#endif
+#if defined (ENOTBLK)
+ {ENOTBLK, "ENOTBLK", "Block device required"},
+#endif
+#if defined (EBUSY)
+ {EBUSY, "EBUSY", "Device busy"},
+#endif
+#if defined (EEXIST)
+ {EEXIST, "EEXIST", "File exists"},
+#endif
+#if defined (EXDEV)
+ {EXDEV, "EXDEV", "Cross-device link"},
+#endif
+#if defined (ENODEV)
+ {ENODEV, "ENODEV", "No such device"},
+#endif
+#if defined (ENOTDIR)
+ {ENOTDIR, "ENOTDIR", "Not a directory"},
+#endif
+#if defined (EISDIR)
+ {EISDIR, "EISDIR", "Is a directory"},
+#endif
+#if defined (EINVAL)
+ {EINVAL, "EINVAL", "Invalid argument"},
+#endif
+#if defined (ENFILE)
+ {ENFILE, "ENFILE", "File table overflow"},
+#endif
+#if defined (EMFILE)
+ {EMFILE, "EMFILE", "Too many open files"},
+#endif
+#if defined (ENOTTY)
+ {ENOTTY, "ENOTTY", "Not a typewriter"},
+#endif
+#if defined (ETXTBSY)
+ {ETXTBSY, "ETXTBSY", "Text file busy"},
+#endif
+#if defined (EFBIG)
+ {EFBIG, "EFBIG", "File too large"},
+#endif
+#if defined (ENOSPC)
+ {ENOSPC, "ENOSPC", "No space left on device"},
+#endif
+#if defined (ESPIPE)
+ {ESPIPE, "ESPIPE", "Illegal seek"},
+#endif
+#if defined (EROFS)
+ {EROFS, "EROFS", "Read-only file system"},
+#endif
+#if defined (EMLINK)
+ {EMLINK, "EMLINK", "Too many links"},
+#endif
+#if defined (EPIPE)
+ {EPIPE, "EPIPE", "Broken pipe"},
+#endif
+#if defined (EDOM)
+ {EDOM, "EDOM", "Math argument out of domain of func"},
+#endif
+#if defined (ERANGE)
+ {ERANGE, "ERANGE", "Math result not representable"},
+#endif
+#if defined (ENOMSG)
+ {ENOMSG, "ENOMSG", "No message of desired type"},
+#endif
+#if defined (EIDRM)
+ {EIDRM, "EIDRM", "Identifier removed"},
+#endif
+#if defined (ECHRNG)
+ {ECHRNG, "ECHRNG", "Channel number out of range"},
+#endif
+#if defined (EL2NSYNC)
+ {EL2NSYNC, "EL2NSYNC", "Level 2 not synchronized"},
+#endif
+#if defined (EL3HLT)
+ {EL3HLT, "EL3HLT", "Level 3 halted"},
+#endif
+#if defined (EL3RST)
+ {EL3RST, "EL3RST", "Level 3 reset"},
+#endif
+#if defined (ELNRNG)
+ {ELNRNG, "ELNRNG", "Link number out of range"},
+#endif
+#if defined (EUNATCH)
+ {EUNATCH, "EUNATCH", "Protocol driver not attached"},
+#endif
+#if defined (ENOCSI)
+ {ENOCSI, "ENOCSI", "No CSI structure available"},
+#endif
+#if defined (EL2HLT)
+ {EL2HLT, "EL2HLT", "Level 2 halted"},
+#endif
+#if defined (EDEADLK)
+ {EDEADLK, "EDEADLK", "Deadlock condition"},
+#endif
+#if defined (ENOLCK)
+ {ENOLCK, "ENOLCK", "No record locks available"},
+#endif
+#if defined (EBADE)
+ {EBADE, "EBADE", "Invalid exchange"},
+#endif
+#if defined (EBADR)
+ {EBADR, "EBADR", "Invalid request descriptor"},
+#endif
+#if defined (EXFULL)
+ {EXFULL, "EXFULL", "Exchange full"},
+#endif
+#if defined (ENOANO)
+ {ENOANO, "ENOANO", "No anode"},
+#endif
+#if defined (EBADRQC)
+ {EBADRQC, "EBADRQC", "Invalid request code"},
+#endif
+#if defined (EBADSLT)
+ {EBADSLT, "EBADSLT", "Invalid slot"},
+#endif
+#if defined (EDEADLOCK)
+ {EDEADLOCK, "EDEADLOCK", "File locking deadlock error"},
+#endif
+#if defined (EBFONT)
+ {EBFONT, "EBFONT", "Bad font file format"},
+#endif
+#if defined (ENOSTR)
+ {ENOSTR, "ENOSTR", "Device not a stream"},
+#endif
+#if defined (ENODATA)
+ {ENODATA, "ENODATA", "No data available"},
+#endif
+#if defined (ETIME)
+ {ETIME, "ETIME", "Timer expired"},
+#endif
+#if defined (ENOSR)
+ {ENOSR, "ENOSR", "Out of streams resources"},
+#endif
+#if defined (ENONET)
+ {ENONET, "ENONET", "Machine is not on the network"},
+#endif
+#if defined (ENOPKG)
+ {ENOPKG, "ENOPKG", "Package not installed"},
+#endif
+#if defined (EREMOTE)
+ {EREMOTE, "EREMOTE", "Object is remote"},
+#endif
+#if defined (ENOLINK)
+ {ENOLINK, "ENOLINK", "Link has been severed"},
+#endif
+#if defined (EADV)
+ {EADV, "EADV", "Advertise error"},
+#endif
+#if defined (ESRMNT)
+ {ESRMNT, "ESRMNT", "Srmount error"},
+#endif
+#if defined (ECOMM)
+ {ECOMM, "ECOMM", "Communication error on send"},
+#endif
+#if defined (EPROTO)
+ {EPROTO, "EPROTO", "Protocol error"},
+#endif
+#if defined (EMULTIHOP)
+ {EMULTIHOP, "EMULTIHOP", "Multihop attempted"},
+#endif
+#if defined (EDOTDOT)
+ {EDOTDOT, "EDOTDOT", "RFS specific error"},
+#endif
+#if defined (EBADMSG)
+ {EBADMSG, "EBADMSG", "Not a data message"},
+#endif
+#if defined (ENAMETOOLONG)
+ {ENAMETOOLONG, "ENAMETOOLONG", "File name too long"},
+#endif
+#if defined (EOVERFLOW)
+ {EOVERFLOW, "EOVERFLOW", "Value too large for defined data type"},
+#endif
+#if defined (ENOTUNIQ)
+ {ENOTUNIQ, "ENOTUNIQ", "Name not unique on network"},
+#endif
+#if defined (EBADFD)
+ {EBADFD, "EBADFD", "File descriptor in bad state"},
+#endif
+#if defined (EREMCHG)
+ {EREMCHG, "EREMCHG", "Remote address changed"},
+#endif
+#if defined (ELIBACC)
+ {ELIBACC, "ELIBACC", "Can not access a needed shared library"},
+#endif
+#if defined (ELIBBAD)
+ {ELIBBAD, "ELIBBAD", "Accessing a corrupted shared library"},
+#endif
+#if defined (ELIBSCN)
+ {ELIBSCN, "ELIBSCN", ".lib section in a.out corrupted"},
+#endif
+#if defined (ELIBMAX)
+ {ELIBMAX, "ELIBMAX", "Attempting to link in too many shared libraries"},
+#endif
+#if defined (ELIBEXEC)
+ {ELIBEXEC, "ELIBEXEC", "Cannot exec a shared library directly"},
+#endif
+#if defined (EILSEQ)
+ {EILSEQ, "EILSEQ", "Illegal byte sequence"},
+#endif
+#if defined (ENOSYS)
+ {ENOSYS, "ENOSYS", "Operation not applicable"},
+#endif
+#if defined (ELOOP)
+ {ELOOP, "ELOOP", "Too many symbolic links encountered"},
+#endif
+#if defined (ERESTART)
+ {ERESTART, "ERESTART", "Interrupted system call should be restarted"},
+#endif
+#if defined (ESTRPIPE)
+ {ESTRPIPE, "ESTRPIPE", "Streams pipe error"},
+#endif
+#if defined (ENOTEMPTY)
+ {ENOTEMPTY, "ENOTEMPTY", "Directory not empty"},
+#endif
+#if defined (EUSERS)
+ {EUSERS, "EUSERS", "Too many users"},
+#endif
+#if defined (ENOTSOCK)
+ {ENOTSOCK, "ENOTSOCK", "Socket operation on non-socket"},
+#endif
+#if defined (EDESTADDRREQ)
+ {EDESTADDRREQ, "EDESTADDRREQ", "Destination address required"},
+#endif
+#if defined (EMSGSIZE)
+ {EMSGSIZE, "EMSGSIZE", "Message too long"},
+#endif
+#if defined (EPROTOTYPE)
+ {EPROTOTYPE, "EPROTOTYPE", "Protocol wrong type for socket"},
+#endif
+#if defined (ENOPROTOOPT)
+ {ENOPROTOOPT, "ENOPROTOOPT", "Protocol not available"},
+#endif
+#if defined (EPROTONOSUPPORT)
+ {EPROTONOSUPPORT, "EPROTONOSUPPORT", "Protocol not supported"},
+#endif
+#if defined (ESOCKTNOSUPPORT)
+ {ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "Socket type not supported"},
+#endif
+#if defined (EOPNOTSUPP)
+ {EOPNOTSUPP, "EOPNOTSUPP", "Operation not supported on transport endpoint"},
+#endif
+#if defined (EPFNOSUPPORT)
+ {EPFNOSUPPORT, "EPFNOSUPPORT", "Protocol family not supported"},
+#endif
+#if defined (EAFNOSUPPORT)
+ {EAFNOSUPPORT, "EAFNOSUPPORT", "Address family not supported by protocol"},
+#endif
+#if defined (EADDRINUSE)
+ {EADDRINUSE, "EADDRINUSE", "Address already in use"},
+#endif
+#if defined (EADDRNOTAVAIL)
+ {EADDRNOTAVAIL, "EADDRNOTAVAIL","Cannot assign requested address"},
+#endif
+#if defined (ENETDOWN)
+ {ENETDOWN, "ENETDOWN", "Network is down"},
+#endif
+#if defined (ENETUNREACH)
+ {ENETUNREACH, "ENETUNREACH", "Network is unreachable"},
+#endif
+#if defined (ENETRESET)
+ {ENETRESET, "ENETRESET", "Network dropped connection because of reset"},
+#endif
+#if defined (ECONNABORTED)
+ {ECONNABORTED, "ECONNABORTED", "Software caused connection abort"},
+#endif
+#if defined (ECONNRESET)
+ {ECONNRESET, "ECONNRESET", "Connection reset by peer"},
+#endif
+#if defined (ENOBUFS)
+ {ENOBUFS, "ENOBUFS", "No buffer space available"},
+#endif
+#if defined (EISCONN)
+ {EISCONN, "EISCONN", "Transport endpoint is already connected"},
+#endif
+#if defined (ENOTCONN)
+ {ENOTCONN, "ENOTCONN", "Transport endpoint is not connected"},
+#endif
+#if defined (ESHUTDOWN)
+ {ESHUTDOWN, "ESHUTDOWN", "Cannot send after transport endpoint shutdown"},
+#endif
+#if defined (ETOOMANYREFS)
+ {ETOOMANYREFS, "ETOOMANYREFS", "Too many references: cannot splice"},
+#endif
+#if defined (ETIMEDOUT)
+ {ETIMEDOUT, "ETIMEDOUT", "Connection timed out"},
+#endif
+#if defined (ECONNREFUSED)
+ {ECONNREFUSED, "ECONNREFUSED", "Connection refused"},
+#endif
+#if defined (EHOSTDOWN)
+ {EHOSTDOWN, "EHOSTDOWN", "Host is down"},
+#endif
+#if defined (EHOSTUNREACH)
+ {EHOSTUNREACH, "EHOSTUNREACH", "No route to host"},
+#endif
+#if defined (EALREADY)
+ {EALREADY, "EALREADY", "Operation already in progress"},
+#endif
+#if defined (EINPROGRESS)
+ {EINPROGRESS, "EINPROGRESS", "Operation now in progress"},
+#endif
+#if defined (ESTALE)
+ {ESTALE, "ESTALE", "Stale NFS file handle"},
+#endif
+#if defined (EUCLEAN)
+ {EUCLEAN, "EUCLEAN", "Structure needs cleaning"},
+#endif
+#if defined (ENOTNAM)
+ {ENOTNAM, "ENOTNAM", "Not a XENIX named type file"},
+#endif
+#if defined (ENAVAIL)
+ {ENAVAIL, "ENAVAIL", "No XENIX semaphores available"},
+#endif
+#if defined (EISNAM)
+ {EISNAM, "EISNAM", "Is a named type file"},
+#endif
+#if defined (EREMOTEIO)
+ {EREMOTEIO, "EREMOTEIO", "Remote I/O error"},
+#endif
+ {0, NULL, NULL}
+};
+
+/* Translation table allocated and initialized at runtime. Indexed by the
+ errno value to find the equivalent symbolic value. */
+
+static 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 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 = (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 = (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 = sys_errlist[errnoval];
+ }
+
+ return (msg);
+}
+
+#endif /* NEED_strerror */
+
+
+/*
+
+NAME
+
+ strerrno -- map an error number to a symbolic name string
+
+SYNOPSIS
+
+ 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.
+
+*/
+
+char *
+strerrno (errnoval)
+ int errnoval;
+{
+ 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 = 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)
+ 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
+
+main ()
+{
+ int errn;
+ int errnmax;
+ char *name;
+ char *msg;
+ char *strerrno ();
+ 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);
+ }
+}
+
+#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..15411ff
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/strsignal.c
@@ -0,0 +1,634 @@
+/* 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 "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__ */
+#ifndef const
+#define const
+#endif
+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> */
+ char *name; /* The equivalent symbolic value */
+ char *msg; /* Short message about this value */
+};
+
+static const struct signal_info signal_table[] =
+{
+#if defined (SIGHUP)
+ {SIGHUP, "SIGHUP", "Hangup"},
+#endif
+#if defined (SIGINT)
+ {SIGINT, "SIGINT", "Interrupt"},
+#endif
+#if defined (SIGQUIT)
+ {SIGQUIT, "SIGQUIT", "Quit"},
+#endif
+#if defined (SIGILL)
+ {SIGILL, "SIGILL", "Illegal instruction"},
+#endif
+#if defined (SIGTRAP)
+ {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)
+ {SIGIOT, "SIGIOT", "IOT trap"},
+#endif
+#if defined (SIGABRT)
+ {SIGABRT, "SIGABRT", "Aborted"},
+#endif
+#if defined (SIGEMT)
+ {SIGEMT, "SIGEMT", "Emulation trap"},
+#endif
+#if defined (SIGFPE)
+ {SIGFPE, "SIGFPE", "Arithmetic exception"},
+#endif
+#if defined (SIGKILL)
+ {SIGKILL, "SIGKILL", "Killed"},
+#endif
+#if defined (SIGBUS)
+ {SIGBUS, "SIGBUS", "Bus error"},
+#endif
+#if defined (SIGSEGV)
+ {SIGSEGV, "SIGSEGV", "Segmentation fault"},
+#endif
+#if defined (SIGSYS)
+ {SIGSYS, "SIGSYS", "Bad system call"},
+#endif
+#if defined (SIGPIPE)
+ {SIGPIPE, "SIGPIPE", "Broken pipe"},
+#endif
+#if defined (SIGALRM)
+ {SIGALRM, "SIGALRM", "Alarm clock"},
+#endif
+#if defined (SIGTERM)
+ {SIGTERM, "SIGTERM", "Terminated"},
+#endif
+#if defined (SIGUSR1)
+ {SIGUSR1, "SIGUSR1", "User defined signal 1"},
+#endif
+#if defined (SIGUSR2)
+ {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)
+ {SIGCLD, "SIGCLD", "Child status changed"},
+#endif
+#if defined (SIGCHLD)
+ {SIGCHLD, "SIGCHLD", "Child status changed"},
+#endif
+#if defined (SIGPWR)
+ {SIGPWR, "SIGPWR", "Power fail/restart"},
+#endif
+#if defined (SIGWINCH)
+ {SIGWINCH, "SIGWINCH", "Window size changed"},
+#endif
+#if defined (SIGURG)
+ {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. */
+ {SIGIO, "SIGIO", "I/O possible"},
+#endif
+#if defined (SIGPOLL)
+ {SIGPOLL, "SIGPOLL", "Pollable event occurred"},
+#endif
+#if defined (SIGSTOP)
+ {SIGSTOP, "SIGSTOP", "Stopped (signal)"},
+#endif
+#if defined (SIGTSTP)
+ {SIGTSTP, "SIGTSTP", "Stopped (user)"},
+#endif
+#if defined (SIGCONT)
+ {SIGCONT, "SIGCONT", "Continued"},
+#endif
+#if defined (SIGTTIN)
+ {SIGTTIN, "SIGTTIN", "Stopped (tty input)"},
+#endif
+#if defined (SIGTTOU)
+ {SIGTTOU, "SIGTTOU", "Stopped (tty output)"},
+#endif
+#if defined (SIGVTALRM)
+ {SIGVTALRM, "SIGVTALRM", "Virtual timer expired"},
+#endif
+#if defined (SIGPROF)
+ {SIGPROF, "SIGPROF", "Profiling timer expired"},
+#endif
+#if defined (SIGXCPU)
+ {SIGXCPU, "SIGXCPU", "CPU time limit exceeded"},
+#endif
+#if defined (SIGXFSZ)
+ {SIGXFSZ, "SIGXFSZ", "File size limit exceeded"},
+#endif
+#if defined (SIGWIND)
+ {SIGWIND, "SIGWIND", "SIGWIND"},
+#endif
+#if defined (SIGPHONE)
+ {SIGPHONE, "SIGPHONE", "SIGPHONE"},
+#endif
+#if defined (SIGLOST)
+ {SIGLOST, "SIGLOST", "Resource lost"},
+#endif
+#if defined (SIGWAITING)
+ {SIGWAITING, "SIGWAITING", "Process's LWPs are blocked"},
+#endif
+#if defined (SIGLWP)
+ {SIGLWP, "SIGLWP", "Signal LWP"},
+#endif
+#if defined (SIGDANGER)
+ {SIGDANGER, "SIGDANGER", "Swap space dangerously low"},
+#endif
+#if defined (SIGGRANT)
+ {SIGGRANT, "SIGGRANT", "Monitor mode granted"},
+#endif
+#if defined (SIGRETRACT)
+ {SIGRETRACT, "SIGRETRACT", "Need to relinguish monitor mode"},
+#endif
+#if defined (SIGMSG)
+ {SIGMSG, "SIGMSG", "Monitor mode data available"},
+#endif
+#if defined (SIGSOUND)
+ {SIGSOUND, "SIGSOUND", "Sound completed"},
+#endif
+#if defined (SIGSAK)
+ {SIGSAK, "SIGSAK", "Secure attention"},
+#endif
+ {0, NULL, NULL}
+};
+
+/* Translation table allocated and initialized at runtime. Indexed by the
+ signal value to find the equivalent symbolic value. */
+
+static 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 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 = (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 = (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
+
+ 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.
+
+*/
+
+char *
+strsignal (signo)
+ int signo;
+{
+ 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 = buf;
+ }
+ else
+ {
+ /* In range, and a valid message. Just return the message. */
+ msg = (char*)sys_siglist[signo];
+ }
+
+ return (msg);
+}
+
+
+/*
+
+NAME
+
+ strsigno -- map an signal number to a symbolic name string
+
+SYNOPSIS
+
+ 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.
+
+*/
+
+char *
+strsigno (signo)
+ int signo;
+{
+ 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 = 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)
+ 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
+
+main ()
+{
+ int signo;
+ int maxsigno;
+ char *name;
+ char *msg;
+ char *strsigno ();
+ char *strsignal ();
+
+ 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);
+ }
+}
+
+#endif
diff --git a/gnu/usr.bin/gdb/libiberty/xmalloc.c b/gnu/usr.bin/gdb/libiberty/xmalloc.c
new file mode 100644
index 0000000..be0c7aa
--- /dev/null
+++ b/gnu/usr.bin/gdb/libiberty/xmalloc.c
@@ -0,0 +1,58 @@
+/* memory allocation routines with error checking.
+ Copyright 1989, 1991, 1993 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 <stdio.h>
+
+#ifdef __STDC__
+#include <stddef.h>
+#else
+#define size_t unsigned long
+#endif
+
+
+PTR
+xmalloc (size)
+ size_t size;
+{
+ char * newmem;
+
+ if ((newmem = (char *) malloc ((int) size)) == NULL)
+ {
+ fprintf (stderr, "\nCan't allocate %u bytes\n", size);
+ exit (1);
+ }
+ return (newmem);
+}
+
+PTR
+xrealloc (oldmem, size)
+ PTR oldmem;
+ size_t size;
+{
+ char * newmem;
+
+ if ((newmem = (char *) realloc ((char *) oldmem, (int) size)) == NULL)
+ {
+ fprintf (stderr, "\nCan't reallocate %u bytes\n", size);
+ exit (1);
+ }
+ return (newmem);
+}
diff --git a/gnu/usr.bin/gdb/main.c b/gnu/usr.bin/gdb/main.c
new file mode 100644
index 0000000..323de87
--- /dev/null
+++ b/gnu/usr.bin/gdb/main.c
@@ -0,0 +1,2241 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 6.6 (Berkeley) 5/13/91";
+#endif /* not lint */
+
+/* Top level for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987, 1988, 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. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "command.h"
+#include "param.h"
+#include "expression.h"
+
+#ifdef USG
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include <sys/file.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#ifdef SET_STACK_LIMIT_HUGE
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int original_stack_limit;
+#endif
+
+/* 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
+
+extern void free ();
+
+/* Version number of GDB, as a string. */
+
+extern char *version;
+
+/*
+ * Declare 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 \"set history\". */
+
+struct cmd_list_element *sethistlist;
+
+/* Chain containing all defined \"unset history\". */
+
+struct cmd_list_element *unsethistlist;
+
+/* stdio stream that command input is being read from. */
+
+FILE *instream;
+
+/* Current working directory. */
+
+char *current_directory;
+
+/* The directory name is actually stored here (usually). */
+static char dirbuf[MAXPATHLEN];
+
+#ifdef KERNELDEBUG
+/* Nonzero if we're debugging /dev/mem or a kernel crash dump */
+
+int kernel_debugging;
+#endif
+
+/* Nonzero to inhibit confirmation of quitting or restarting
+ a stopped inferior. */
+int inhibit_confirm;
+
+/* Nonzero if we can write in text or core file */
+
+int writeable_text;
+
+/* The number of lines on a page, and the number of spaces
+ in a line. */
+int linesize, pagesize;
+
+/* Nonzero if we should refrain from using an X window. */
+
+int inhibit_windows = 0;
+
+/* Function to call before reading a command, if nonzero.
+ The function receives two args: an input stream,
+ and a prompt string. */
+
+void (*window_hook) ();
+
+extern int frame_file_full_name;
+int xgdb_verbose;
+
+void execute_command();
+void free_command_lines ();
+char *gdb_readline ();
+char *command_line_input ();
+static void initialize_main ();
+static void initialize_cmd_lists ();
+void command_loop ();
+static void source_command ();
+static void print_gdb_version ();
+static void float_handler ();
+static void cd_command ();
+
+char *getenv ();
+
+/* 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;
+
+
+/* This is how `error' returns to command level. */
+
+jmp_buf to_top_level;
+
+void
+return_to_top_level ()
+{
+ quit_flag = 0;
+ immediate_quit = 0;
+ clear_breakpoint_commands ();
+ clear_momentary_breakpoints ();
+ disable_current_display ();
+ do_cleanups (0);
+ longjmp (to_top_level, 1);
+}
+
+/* Call FUNC with arg ARG, catching any errors.
+ If there is no error, return the value returned by FUNC.
+ If there is an error, return zero after printing ERRSTRING
+ (which is in addition to the specific error message already printed). */
+
+int
+catch_errors (func, arg, errstring)
+ int (*func) ();
+ int arg;
+ char *errstring;
+{
+ jmp_buf saved;
+ int val;
+ struct cleanup *saved_cleanup_chain;
+
+ saved_cleanup_chain = save_cleanups ();
+
+ bcopy (to_top_level, saved, sizeof (jmp_buf));
+
+ if (setjmp (to_top_level) == 0)
+ val = (*func) (arg);
+ else
+ {
+ fprintf (stderr, "%s\n", errstring);
+ val = 0;
+ }
+
+ restore_cleanups (saved_cleanup_chain);
+
+ bcopy (saved, to_top_level, sizeof (jmp_buf));
+ return val;
+}
+
+/* Handler for SIGHUP. */
+
+static void
+disconnect ()
+{
+ kill_inferior_fast ();
+ signal (SIGHUP, SIG_DFL);
+ kill (getpid (), SIGHUP);
+}
+
+/* Clean up on error during a "source" command (or execution of a
+ user-defined command).
+ Close the file opened by the command
+ and restore the previous input stream. */
+
+static void
+source_cleanup (stream)
+ FILE *stream;
+{
+ /* Instream may be 0; set to it when executing user-defined command. */
+ if (instream)
+ fclose (instream);
+ instream = stream;
+}
+
+/*
+ * Source $HOME/.gdbinit and $cwd/.gdbinit.
+ * If X is enabled, also $HOME/.xgdbinit and $cwd/.xgdbinit.source
+ */
+void
+source_init_files()
+{
+ char *homedir, initfile[256];
+ int samedir = 0;
+
+ /* Read init file, if it exists in home directory */
+ homedir = getenv ("HOME");
+ if (homedir) {
+ struct stat homebuf, cwdbuf;
+
+ sprintf(initfile, "%s/.gdbinit", homedir);
+ if (access (initfile, R_OK) == 0)
+ if (!setjmp (to_top_level))
+ source_command (initfile);
+ if (!inhibit_windows) {
+ sprintf(initfile, "%s/.xgdbinit", homedir);
+ if (access (initfile, R_OK) == 0)
+ if (!setjmp (to_top_level))
+ source_command (initfile);
+ }
+ /* Determine if current directory is the same as the home
+ directory, so we don't source the same file twice. */
+
+ bzero (&homebuf, sizeof (struct stat));
+ bzero (&cwdbuf, sizeof (struct stat));
+
+ stat(homedir, &homebuf);
+ stat(".", &cwdbuf);
+
+ samedir = bcmp(&homebuf, &cwdbuf, sizeof(struct stat)) == 0;
+ }
+ /* Read the input file in the current directory, *if* it isn't
+ the same file (it should exist, also). */
+ if (!samedir) {
+ if (access (".gdbinit", R_OK) == 0)
+ if (!setjmp (to_top_level))
+ source_command (".gdbinit");
+ if (access (".xgdbinit", R_OK) == 0)
+ if (!setjmp (to_top_level))
+ source_command (".xgdbinit");
+ }
+}
+
+
+int
+main (argc, argv, envp)
+ int argc;
+ char **argv;
+ char **envp;
+{
+ int count;
+ int inhibit_gdbinit = 0;
+ int quiet = 1;
+ int batch = 0;
+ register int i;
+ char *cp;
+
+ /* XXX Windows only for xgdb. */
+ char *strrchr();
+ if (cp = strrchr(argv[0], '/'))
+ ++cp;
+ else
+ cp = argv[0];
+ if (*cp != 'x')
+ inhibit_windows = 1;
+
+#if defined (ALIGN_STACK_ON_STARTUP)
+ i = (int) &count & 0x3;
+ if (i != 0)
+ alloca (4 - i);
+#endif
+
+ quit_flag = 0;
+ linesize = 100;
+ line = (char *) xmalloc (linesize);
+ *line = 0;
+ instream = stdin;
+
+ getwd (dirbuf);
+ current_directory = dirbuf;
+
+#ifdef SET_STACK_LIMIT_HUGE
+ {
+ struct rlimit rlim;
+
+ /* Set the stack limit huge so that alloca (particularly stringtab
+ * in dbxread.c) does not fail. */
+ getrlimit (RLIMIT_STACK, &rlim);
+ original_stack_limit = rlim.rlim_cur;
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit (RLIMIT_STACK, &rlim);
+ }
+#endif /* SET_STACK_LIMIT_HUGE */
+
+ /* Look for flag arguments. */
+
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "-q") || !strcmp (argv[i], "-quiet"))
+ quiet = 1;
+ else if (!strcmp (argv[i], "-nx"))
+ inhibit_gdbinit = 1;
+ else if (!strcmp (argv[i], "-nw"))
+ inhibit_windows = 1;
+ else if (!strcmp (argv[i], "-batch"))
+ batch = 1, quiet = 1;
+ else if (!strcmp (argv[i], "-fullname"))
+ frame_file_full_name = 1;
+ else if (!strcmp (argv[i], "-xgdb_verbose"))
+ xgdb_verbose = 1;
+ /* -help: print a summary of command line switches. */
+ else if (!strcmp (argv[i], "-help"))
+ {
+ fputs ("\
+This is GDB, the GNU debugger. Use the command\n\
+ gdb [options] [executable [core-file]]\n\
+to enter the debugger.\n\
+\n\
+Options available are:\n\
+ -help Print this message.\n\
+ -quiet Do not print version number on startup.\n\
+ -fullname Output information used by 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\
+ -k Kernel debugging.\n\
+ -w Writeable text.\n\
+ -v Print GNU message and version number on startup.\n\
+ -nc Don't confirm quit or run commands.\n\
+\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", stderr);
+ /* Exiting after printing this message seems like
+ the most useful thing to do. */
+ exit (0);
+ }
+#ifdef KERNELDEBUG
+ else if (!strcmp (argv[i], "-k"))
+ kernel_debugging = 1;
+#endif
+ else if (!strcmp (argv[i], "-w"))
+ writeable_text = 1;
+ else if (!strcmp (argv[i], "-v"))
+ quiet = 0;
+ else if (!strcmp (argv[i], "-nc"))
+ inhibit_confirm = 1;
+ else if (argv[i][0] == '-')
+ /* Other options take arguments, so don't confuse an
+ argument with an option. */
+ i++;
+ }
+
+ /* Run the init function of each source file */
+
+ initialize_cmd_lists (); /* This needs to be done first */
+ initialize_all_files ();
+ initialize_main (); /* But that omits this file! Do it now */
+ initialize_signals ();
+
+ if (!quiet)
+ print_gdb_version ();
+
+ /* Process the command line arguments. */
+
+ count = 0;
+ for (i = 1; i < argc; i++)
+ {
+ extern void exec_file_command (), symbol_file_command ();
+ extern void core_file_command ();
+ register char *arg = argv[i];
+ /* Args starting with - say what to do with the following arg
+ as a filename. */
+ if (arg[0] == '-')
+ {
+ extern void tty_command (), directory_command ();
+
+ if (!strcmp (arg, "-q") || !strcmp (arg, "-nx")
+ || !strcmp (arg, "-quiet") || !strcmp (arg, "-batch")
+ || !strcmp (arg, "-fullname") || !strcmp (arg, "-nw")
+ || !strcmp (arg, "-xgdb_verbose")
+ || !strcmp (arg, "-help")
+ || !strcmp (arg, "-k")
+ || !strcmp (arg, "-w")
+ || !strcmp (arg, "-v")
+ || !strcmp (arg, "-nc"))
+ /* Already processed above */
+ continue;
+
+ if (++i == argc)
+ fprintf (stderr, "No argument follows \"%s\".\n", arg);
+ if (!setjmp (to_top_level))
+ {
+ /* -s foo: get syms from foo. -e foo: execute foo.
+ -se foo: do both with foo. -c foo: use foo as core dump. */
+ if (!strcmp (arg, "-se"))
+ {
+ exec_file_command (argv[i], !batch);
+ symbol_file_command (argv[i], !batch);
+ }
+ else if (!strcmp (arg, "-s") || !strcmp (arg, "-symbols"))
+ symbol_file_command (argv[i], !batch);
+ else if (!strcmp (arg, "-e") || !strcmp (arg, "-exec"))
+ exec_file_command (argv[i], !batch);
+ else if (!strcmp (arg, "-c") || !strcmp (arg, "-core"))
+ core_file_command (argv[i], !batch);
+ /* -x foo: execute commands from foo. */
+ else if (!strcmp (arg, "-x") || !strcmp (arg, "-command")
+ || !strcmp (arg, "-commands"))
+ source_command (argv[i]);
+ /* -d foo: add directory `foo' to source-file directory
+ search-list */
+ else if (!strcmp (arg, "-d") || !strcmp (arg, "-dir")
+ || !strcmp (arg, "-directory"))
+ directory_command (argv[i], 0);
+ /* -cd FOO: specify current directory as FOO.
+ GDB remembers the precise string FOO as the dirname. */
+ else if (!strcmp (arg, "-cd"))
+ {
+ cd_command (argv[i], 0);
+ init_source_path ();
+ }
+ /* -t /def/ttyp1: use /dev/ttyp1 for inferior I/O. */
+ else if (!strcmp (arg, "-t") || !strcmp (arg, "-tty"))
+ tty_command (argv[i], 0);
+
+ else
+ error ("Unknown command-line switch: \"%s\"\n", arg);
+ }
+ }
+ else
+ {
+ /* Args not thus accounted for
+ are treated as, first, the symbol/executable file
+ and, second, the core dump file. */
+ count++;
+ if (!setjmp (to_top_level))
+ switch (count)
+ {
+ case 1:
+ exec_file_command (arg, !batch);
+ symbol_file_command (arg, !batch);
+ break;
+
+ case 2:
+ core_file_command (arg, !batch);
+ break;
+
+ case 3:
+ fprintf (stderr, "Excess command line args ignored. (%s%s)\n",
+ arg, (i == argc - 1) ? "" : " ...");
+ }
+ }
+ }
+
+ if (!inhibit_gdbinit)
+ source_init_files();
+
+ if (batch)
+ {
+#if 0
+ fatal ("Attempt to read commands from stdin in batch mode.");
+#endif
+ /* We have hit the end of the batch file. */
+ exit (0);
+ }
+
+ if (!quiet)
+ printf ("Type \"help\" for a list of commands.\n");
+
+ /* The command loop. */
+
+ while (1)
+ {
+ if (!setjmp (to_top_level))
+ command_loop ();
+ if (ISATTY(stdin))
+ clearerr (stdin); /* Don't get hung if C-d is typed. */
+ else if (feof(instream)) /* Avoid endless loops for redirected stdin */
+ break;
+ }
+ exit (0);
+}
+
+
+static void
+do_nothing ()
+{
+}
+
+/* Read commands from `instream' and execute them
+ until end of file. */
+void
+command_loop ()
+{
+ struct cleanup *old_chain;
+ register int toplevel = (instream == stdin);
+ register int interactive = (toplevel && ISATTY(stdin));
+
+ while (!feof (instream))
+ {
+ register char *cmd_line;
+
+ quit_flag = 0;
+ if (interactive)
+ reinitialize_more_filter ();
+ old_chain = make_cleanup (do_nothing, 0);
+ cmd_line = command_line_input (prompt, toplevel);
+ execute_command (cmd_line, toplevel);
+ /* Do any commands attached to breakpoint we stopped at. */
+ do_breakpoint_commands ();
+ do_cleanups (old_chain);
+ }
+}
+
+/* Commands call this if they do not want to be repeated by null lines. */
+
+void
+dont_repeat ()
+{
+ /* 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 PROMPT once at the start.
+ Action is compatible with "readline" (i.e., space for typing is
+ malloced & should be freed by caller). */
+char *
+gdb_readline (prompt)
+ char *prompt;
+{
+ int c;
+ char *result;
+ int input_index = 0;
+ int result_size = 80;
+
+ if (prompt)
+ {
+ printf (prompt);
+ fflush (stdout);
+ }
+
+ result = (char *) xmalloc (result_size);
+
+ while (1)
+ {
+ c = fgetc (instream ? instream : stdin);
+ if (c == EOF)
+ {
+ free(result);
+ return ((char *)0);
+ }
+ if (c == '\n')
+ break;
+
+ result[input_index++] = c;
+ if (input_index >= result_size)
+ {
+ result_size <= 1;
+ result = (char *)xrealloc(result, result_size);
+ }
+ }
+ result[input_index++] = '\0';
+ return result;
+}
+
+/* Declaration for fancy readline with command line editing. */
+char *readline ();
+
+/* 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;
+
+/* Variables which are necessary for fancy command line editing. */
+char *gdb_completer_word_break_characters =
+ " \t\n!@#$%^&*()-+=|~`}{[]\"';:?/>.<,";
+
+/* Functions that are used as part of the fancy command line editing. */
+
+/* Generate symbol names one by one for the completer. If STATE is
+ zero, then we need to initialize, otherwise the initialization has
+ already taken place. TEXT is what we expect the symbol to start
+ with. 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. */
+char *
+symbol_completion_function (text, state)
+ char *text;
+ int state;
+{
+ char **make_symbol_completion_list ();
+ static char **list = (char **)NULL;
+ static int index;
+ char *output;
+ extern char *rl_line_buffer;
+ extern int rl_point;
+ char *tmp_command, *p;
+ struct cmd_list_element *c, *result_list;
+
+ if (!state)
+ {
+ /* Free the storage used by LIST, but not by the strings inside. This is
+ because rl_complete_internal () frees the strings. */
+ if (list)
+ free (list);
+ list = 0;
+ index = 0;
+
+ /* 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';
+
+ 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)
+ /* He's typed something unrecognizable. Sigh. */
+ list = (char **) 0;
+ else if (c == (struct cmd_list_element *) -1)
+ {
+ if (p + strlen(text) != tmp_command + rl_point)
+ error ("Unrecognized command.");
+
+ /* He's typed something ambiguous. This is easier. */
+ if (result_list)
+ list = complete_on_cmdlist (*result_list->prefixlist, text);
+ else
+ list = complete_on_cmdlist (cmdlist, text);
+ }
+ else
+ {
+ /* If we've gotten this far, gdb has recognized a full
+ command. There are several possibilities:
+
+ 1) We need to complete on the command.
+ 2) We need to complete on the possibilities coming after
+ the command.
+ 2) We need to complete the text of what comes after the
+ command. */
+
+ if (!*p && *text)
+ /* Always (might be longer versions of thie command). */
+ list = complete_on_cmdlist (result_list, text);
+ else if (!*p && !*text)
+ {
+ if (c->prefixlist)
+ list = complete_on_cmdlist (*c->prefixlist, "");
+ else
+ list = make_symbol_completion_list ("");
+ }
+ else
+ {
+ if (c->prefixlist && !c->allow_unknown)
+ {
+ *p = '\0';
+ error ("\"%s\" command requires a subcommand.",
+ tmp_command);
+ }
+ else
+ list = make_symbol_completion_list (text);
+ }
+ }
+ }
+
+ /* If the debugged program wasn't compiled with symbols, or if we're
+ clearly completing on a command and no command matches, return
+ NULL. */
+ if (!list)
+ return ((char *)NULL);
+
+ output = list[index];
+ if (output)
+ index++;
+
+ return (output);
+}
+
+
+void
+print_prompt ()
+{
+ if (prompt)
+ {
+ printf ("%s", prompt);
+ fflush (stdout);
+ }
+}
+
+
+#ifdef HAVE_TERMIO
+#include <termio.h>
+static struct termio norm_tty;
+
+static void
+suspend_sig()
+{
+ int tty = fileno(stdin);
+ struct termio cur_tty;
+
+ ioctl(tty, TCGETA, &cur_tty);
+ ioctl(tty, TCSETAW, &norm_tty);
+
+ (void) sigsetmask(0);
+ signal(SIGTSTP, SIG_DFL);
+ kill(0, SIGTSTP);
+
+ /*
+ * we've just been resumed -- current tty params become new
+ * 'normal' params (in case tset/stty was done while we were
+ * suspended). Merge values that readline might have changed
+ * into new params, then restore term mode.
+ */
+ ioctl(tty, TCGETA, &norm_tty);
+ cur_tty.c_lflag = (cur_tty.c_lflag & (ICANON|ECHO|ISIG)) |
+ (norm_tty.c_lflag &~ (ICANON|ECHO|ISIG));
+ cur_tty.c_iflag = (cur_tty.c_iflag & (IXON|ISTRIP|INPCK)) |
+ (norm_tty.c_iflag &~ (IXON|ISTRIP|INPCK));
+ ioctl(tty, TCSETAW, &cur_tty);
+
+ signal(SIGTSTP, suspend_sig);
+ print_prompt();
+
+ /*
+ * Forget about any previous command -- null line now will do
+ * nothing.
+ */
+ dont_repeat();
+}
+
+#else
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sgtty.h>
+
+static struct sgttyb norm_tty;
+static struct tchars norm_tchars;
+static struct ltchars norm_ltchars;
+static int norm_lflags;
+
+#ifdef PASS8
+#define RL_TFLAGS (RAW|CRMOD|ECHO|CBREAK|PASS8)
+#else
+#define RL_TFLAGS (RAW|CRMOD|ECHO|CBREAK)
+#endif
+
+static void
+suspend_sig()
+{
+ int tty = fileno(stdin);
+ struct sgttyb cur_tty;
+ struct tchars cur_tchars;
+ struct ltchars cur_ltchars;
+ int cur_lflags;
+ int cur_flags;
+
+ ioctl(tty, TIOCGETP, &cur_tty);
+ ioctl(tty, TIOCGETC, &cur_tchars);
+ ioctl(tty, TIOCLGET, &cur_lflags);
+ ioctl(tty, TIOCGLTC, &cur_ltchars);
+
+ ioctl(tty, TIOCSETP, &norm_tty);
+ ioctl(tty, TIOCSETC, &norm_tchars);
+ ioctl(tty, TIOCLSET, &norm_lflags);
+ ioctl(tty, TIOCSLTC, &norm_ltchars);
+
+ (void) sigsetmask(0);
+ signal(SIGTSTP, SIG_DFL);
+ kill(0, SIGTSTP);
+
+ /*
+ * we've just been resumed -- current tty params become new
+ * 'normal' params (in case tset/stty was done while we were
+ * suspended). Merge values that readline might have changed
+ * into new params, then restore term mode.
+ */
+ ioctl(tty, TIOCGETP, &norm_tty);
+ cur_flags = cur_tty.sg_flags;
+ cur_tty = norm_tty;
+ cur_tty.sg_flags = (cur_tty.sg_flags &~ RL_TFLAGS)
+ | (cur_flags & RL_TFLAGS);
+
+ ioctl(tty, TIOCLGET, &norm_lflags);
+#ifdef LPASS8
+ cur_lflags = (cur_lflags &~ LPASS8) | (cur_flags & LPASS8);
+#endif
+ ioctl(tty, TIOCGETC, &norm_tchars);
+ ioctl(tty, TIOCGLTC, &norm_ltchars);
+
+ ioctl(tty, TIOCSETP, &cur_tty);
+ ioctl(tty, TIOCSETC, &cur_tchars);
+ ioctl(tty, TIOCLSET, &cur_lflags);
+ ioctl(tty, TIOCSLTC, &cur_ltchars);
+
+ signal(SIGTSTP, suspend_sig);
+ print_prompt();
+
+ /*
+ * Forget about any previous command -- null line now will do
+ * nothing.
+ */
+ dont_repeat();
+}
+#endif /* HAVE_TERMIO */
+
+/* Initialize signal handlers. */
+initialize_signals ()
+{
+ extern void request_quit ();
+ int tty = fileno(stdin);
+
+ 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 will (apparently) affect the
+ GDB process as well as the inferior (the signal handling tables
+ being shared between the two, apparently). 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);
+
+ ioctl(tty, TIOCGETP, &norm_tty);
+ ioctl(tty, TIOCLGET, &norm_lflags);
+ ioctl(tty, TIOCGETC, &norm_tchars);
+ ioctl(tty, TIOCGLTC, &norm_ltchars);
+ signal(SIGTSTP, suspend_sig);
+}
+
+char *
+finish_command_input(inputline, repeat, interactive)
+ register char *inputline;
+ int repeat;
+ int interactive;
+{
+ static char *do_free;
+
+ if (do_free) {
+ free(do_free);
+ do_free = NULL;
+ }
+
+ /* Do history expansion if that is wished. */
+ if (interactive && history_expansion_p) {
+ int expanded;
+
+ expanded = history_expand(inputline, &do_free);
+ if (expanded) {
+ /* Print the changes. */
+ puts(do_free);
+
+ /* An error acts like no input. */
+ if (expanded < 0) {
+ *do_free = 0;
+ return (do_free);
+ }
+ }
+ inputline = do_free;
+ }
+ /* get rid of any leading whitespace */
+ while (isspace(*inputline))
+ ++inputline;
+ /*
+ * If we just got an empty line, and that is supposed to repeat the
+ * previous command, return the value in the global buffer.
+ */
+ if (*inputline == 0) {
+ if (repeat)
+ return (line);
+ } else if (interactive)
+ add_history(inputline);
+
+ /*
+ * If line is a comment, clear it out.
+ * Note: 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 '#'.
+ */
+ if (*inputline == '#')
+ *inputline = 0;
+ else if (repeat) {
+ /* Save into global buffer. */
+ register int i = strlen(inputline) + 1;
+
+ if (i > linesize) {
+ line = xrealloc(line, i);
+ linesize = i;
+ }
+ strcpy(line, inputline);
+ }
+ return (inputline);
+}
+
+static char *
+get_a_cmd_line(prompt, interactive)
+ char *prompt;
+ int interactive;
+{
+ register char *cp;
+
+ /* Control-C quits instantly if typed while reading input. */
+ immediate_quit++;
+ if (interactive && command_editing_p) {
+ extern void (*rl_event_hook)();
+
+ rl_event_hook = window_hook;
+ cp = readline(prompt);
+ } else {
+ if (interactive) {
+ if (window_hook) {
+ print_prompt();
+ (*window_hook)();
+ }
+ } else
+ prompt = NULL;
+ cp = gdb_readline(prompt);
+ }
+ --immediate_quit;
+ return (cp);
+}
+
+/* Read one line from the command input stream `instream'
+ Returns the address of the start of the line.
+
+ *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(prompt, repeat)
+ char *prompt;
+ int repeat;
+{
+ static char *do_free;
+ register int interactive = (instream == stdin && ISATTY(instream));
+ register char *cp;
+ register int i;
+
+ if (do_free) {
+ free(do_free);
+ do_free = NULL;
+ }
+ cp = get_a_cmd_line(prompt, interactive);
+
+ /*
+ * handle continued lines (this loop is not particularly
+ * efficient because it's rare).
+ */
+ while (cp && cp[i = strlen(cp) - 1] == '\\') {
+ register char *np = get_a_cmd_line(prompt, interactive);
+ register int j;
+
+ if (np == NULL) {
+ cp[i] = 0;
+ break;
+ }
+ j = strlen(np);
+ cp = xrealloc(cp, i + j + 1);
+ strcpy(cp + i, np);
+ free(np);
+ }
+ if (cp == NULL)
+ return ("");
+ do_free = cp;
+ return (finish_command_input(cp, repeat, interactive));
+}
+
+
+#define MAX_USER_ARGS 32
+
+static struct user_args {
+ struct {
+ char *arg;
+ int len;
+ } a[10];
+} uargs[MAX_USER_ARGS];
+
+static struct user_args *user_arg = uargs;
+
+static void
+arg_cleanup(ap)
+ struct user_args *ap;
+{
+ user_arg = ap;
+}
+
+/* Bind arguments $arg0, $arg1, ..., for a user defined command. */
+struct cleanup *
+setup_user_args(p)
+ char *p;
+{
+ register int i;
+ struct cleanup *old_chain = make_cleanup(arg_cleanup, user_arg);
+
+ if (++user_arg >= &uargs[MAX_USER_ARGS])
+ error("user defined functions nested too deeply\n");
+
+ bzero(user_arg, sizeof(*user_arg));
+
+ i = 0;
+ while (*p) {
+ while (isspace(*p))
+ ++p;
+ user_arg->a[i].arg = p;
+ while (*p && ! isspace(*p))
+ ++p;
+ user_arg->a[i].len = p - user_arg->a[i].arg;
+ ++i;
+ }
+ return (old_chain);
+}
+
+static char *
+findarg(str)
+ register char *str;
+{
+ register char *cp = str;
+ extern char *index();
+
+ while (cp = index(cp, '$')) {
+ if (strncmp(cp, "$arg", 4) == 0 && isdigit(cp[4]))
+ return (cp);
+ ++cp;
+ }
+ return (char *)0;
+}
+
+/* expand arguments from "line" into "new" */
+static void
+expand_args(line, new)
+ register char *line, *new;
+{
+ register char *cp = findarg(line);
+
+ while (cp = findarg(line)) {
+ int i, len;
+
+ bcopy(line, new, cp - line);
+ new += cp - line;
+ i = cp[4] - '0';
+ if (len = user_arg->a[i].len) {
+ bcopy(user_arg->a[i].arg, new, len);
+ new += len;
+ }
+ line = cp + 5;
+ }
+ strcpy(new, line);
+}
+
+/* expand any arguments in "line" then execute the result */
+static void
+expand_and_execute(line, from_tty)
+ char *line;
+ int from_tty;
+{
+ void execute_command();
+ char new[1024];
+
+ if (! findarg(line)) {
+ execute_command(line, from_tty);
+ return;
+ }
+ expand_args(line, new);
+ execute_command(new, from_tty);
+}
+
+char *
+read_one_command_line(prompt, from_tty)
+ char *prompt;
+{
+ register char *p, *p1;
+
+ dont_repeat();
+ p = command_line_input(prompt, from_tty);
+
+ /* Remove trailing blanks. */
+ p1 = p + strlen(p);
+ while (--p1 > p && (*p1 == ' ' || *p1 == '\t'))
+ ;
+ *++p1 = 0;
+ return (p);
+}
+
+static char cmd_prompt[] = " > ";
+
+int
+parse_control_structure(rootcmd, from_tty, level)
+ struct command_line *rootcmd;
+ int from_tty;
+{
+ struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd));
+ char *prompt;
+
+ ++level;
+ prompt = from_tty? &cmd_prompt[sizeof(cmd_prompt) - 1 - 2*level] :
+ (char *)0;
+ bzero(cmd, sizeof(*cmd));
+ rootcmd->body = cmd;
+ while (1) {
+ char *p = read_one_command_line(prompt, from_tty);
+
+ p = savestring(p, strlen(p));
+ cmd->line = p;
+ if (!strncmp(p, "while ", 6)) {
+ cmd->type = CL_WHILE;
+ if (parse_control_structure(cmd, from_tty, level))
+ return (1);
+ } else if (!strncmp(p, "if ", 3)) {
+ cmd->type = CL_IF;
+ if (parse_control_structure(cmd, from_tty, level)) {
+ struct command_line *tmp;
+ int stat;
+
+ cmd->elsebody = cmd->body;
+ stat = parse_control_structure(cmd, from_tty,
+ level);
+ tmp = cmd->elsebody;
+ cmd->elsebody = cmd->body;
+ cmd->body = tmp;
+ if (stat)
+ return (1);
+ }
+ } else if (!strcmp(p, "else")) {
+ cmd->type = CL_END;
+ return (1);
+ } else if (!strcmp(p, "end")) {
+ cmd->type = CL_END;
+ return (0);
+ } else if (!strcmp(p, "exitloop")) {
+ cmd->type = CL_EXITLOOP;
+ } else {
+ cmd->type = CL_NORMAL;
+ }
+ cmd->next = (struct command_line *)xmalloc(sizeof(*cmd));
+ cmd = cmd->next;
+ bzero(cmd, sizeof(*cmd));
+ }
+ /* NOTREACHED */
+}
+
+int
+execute_control_structure(cmd)
+ register struct command_line *cmd;
+{
+ char expn[1024];
+ struct expression *cond;
+ int stat;
+
+ while (cmd) {
+ QUIT;
+ switch (cmd->type) {
+ case CL_END:
+ return (0);
+ case CL_NORMAL:
+ expand_and_execute(cmd->line, 0);
+ break;
+ case CL_WHILE:
+ expand_args(cmd->line + 6, expn);
+ cond = parse_c_expression(expn);
+ while (breakpoint_cond_eval(cond) == 0)
+ if (execute_control_structure(cmd->body))
+ break;
+ free(cond);
+ break;
+ case CL_IF:
+ expand_args(cmd->line + 3, expn);
+ cond = parse_c_expression(expn);
+ stat = breakpoint_cond_eval(cond);
+ free(cond);
+ if (stat == 0) {
+ if (execute_control_structure(cmd->body))
+ return (1);
+ } else if (cmd->elsebody) {
+ if (execute_control_structure(cmd->elsebody))
+ return (1);
+ }
+ break;
+ case CL_EXITLOOP:
+ return (1);
+ }
+ cmd = cmd->next;
+ }
+ free_all_values();
+}
+
+execute_command_lines(cmd)
+ struct command_line *cmd;
+{
+ struct cleanup *old_chain = make_cleanup(source_cleanup, instream);
+
+ /*
+ * Set the instream to 0, indicating execution of a user-defined
+ * function.
+ */
+ ++immediate_quit;
+ instream = (FILE *) 0;
+ (void)execute_control_structure(cmd);
+ --immediate_quit;
+ do_cleanups(old_chain);
+}
+
+/* do following command lines if expression true */
+if_command(p, from_tty)
+ char *p;
+ int from_tty;
+{
+ struct cleanup *old_chain;
+ struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd));
+ char buf[128];
+
+ sprintf(buf, "if %s", p);
+
+ bzero(cmd, sizeof(*cmd));
+ old_chain = make_cleanup(free_command_lines, cmd);
+ cmd->type = CL_IF;
+ cmd->line = savestring(buf, strlen(buf));
+ /* XXX cmd->line? */
+ if (parse_control_structure(cmd, from_tty, 0)) {
+ struct command_line *tmp;
+
+ cmd->elsebody = cmd->body;
+ (void) parse_control_structure(cmd, from_tty, 0);
+ tmp = cmd->elsebody;
+ cmd->elsebody = cmd->body;
+ cmd->body = tmp;
+ }
+ (void) execute_command_lines(cmd);
+ do_cleanups(old_chain);
+}
+
+/* do following command lines while expression true */
+while_command(p, from_tty)
+ char *p;
+ int from_tty;
+{
+ struct cleanup *old_chain;
+ struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd));
+ char buf[128];
+
+ sprintf(buf, "while %s", p);
+
+ bzero(cmd, sizeof(*cmd));
+ old_chain = make_cleanup(free_command_lines, cmd);
+ cmd->type = CL_WHILE;
+ cmd->line = savestring(buf, strlen(buf));
+ (void)parse_control_structure(cmd, from_tty, 0);
+ (void)execute_command_lines(cmd);
+ 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 struct command_line *cmdlines;
+
+ free_all_values();
+ if (*p) {
+ c = lookup_cmd(&p, cmdlist, "", 0, 1);
+ if (c->function == 0)
+ error("That is not a command, just a help topic.");
+ else if (c->class == (int) class_user) {
+ struct cleanup *old_chain = setup_user_args(p);
+
+ cmdlines = (struct command_line *) c->function;
+ if (cmdlines)
+ (void)execute_command_lines(cmdlines);
+
+ do_cleanups(old_chain);
+ } else
+ /* Pass null arg rather than an empty one. */
+ (*c->function) (*p ? p : 0, from_tty);
+ }
+}
+
+/*
+ * 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(from_tty)
+ int from_tty;
+{
+ struct cleanup *old_chain;
+ struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd));
+ struct command_line *next;
+
+ bzero(cmd, sizeof(*cmd));
+ old_chain = make_cleanup(free_command_lines, cmd);
+ cmd->type = CL_NOP;
+ (void)parse_control_structure(cmd, from_tty, 0);
+ dont_repeat();
+ discard_cleanups(old_chain);
+ next = cmd->body;
+ free(cmd);
+ return (next);
+}
+
+/* Free a chain of struct command_line's. */
+
+void
+free_command_lines(cmds)
+ struct command_line *cmds;
+{
+ struct command_line *next;
+
+ while (cmds) {
+ if (cmds->body)
+ free(cmds->body);
+ if (cmds->elsebody)
+ free(cmds->elsebody);
+ if (cmds->line)
+ free(cmds->line);
+ next = cmds->next;
+ free(cmds);
+ cmds = next;
+ }
+}
+
+/* Add an element to the list of info subcommands. */
+
+void
+add_info (name, fun, doc)
+ char *name;
+ void (*fun) ();
+ 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. */
+
+static void
+info_command ()
+{
+ printf ("\"info\" must be followed by the name of an info command.\n");
+ help_list (infolist, "info ", -1, stdout);
+}
+
+/* Add an element to the list of commands. */
+
+void
+add_com (name, class, fun, doc)
+ char *name;
+ int class;
+ void (*fun) ();
+ 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;
+ int 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);
+}
+
+static void
+help_command (command, from_tty)
+ char *command;
+ int from_tty; /* Ignored */
+{
+ help_cmd (command, 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 (!(*p >= 'A' && *p <= 'Z')
+ && !(*p >= 'a' && *p <= 'z')
+ && !(*p >= '0' && *p <= '9')
+ && *p != '-')
+ error ("Junk in argument list: \"%s\"", p);
+ p++;
+ }
+}
+
+static void
+define_command (comname, from_tty)
+ char *comname;
+ int from_tty;
+{
+ register struct command_line *cmds;
+ register struct cmd_list_element *c;
+ char *tem = comname;
+
+ validate_comname (comname);
+
+ c = lookup_cmd (&tem, cmdlist, "", -1, 1);
+ if (c)
+ {
+ if (c->class == (int) class_user || c->class == (int) class_alias)
+ tem = "Redefine command \"%s\"? ";
+ else
+ tem = "Really redefine built-in command \"%s\"? ";
+ if (!query (tem, comname))
+ error ("Command \"%s\" not redefined.", comname);
+ }
+
+ if (from_tty)
+ {
+ printf ("Type commands for definition of \"%s\".\n\
+End with a line saying just \"end\".\n", comname);
+ fflush (stdout);
+ }
+ comname = savestring (comname, strlen (comname));
+
+ cmds = read_command_lines (from_tty);
+
+ if (c && c->class == (int) class_user)
+ free_command_lines (c->function);
+
+ add_com (comname, class_user, cmds,
+ (c && c->class == (int) class_user)
+ ? c->doc : savestring ("User-defined.", 13));
+}
+
+static void
+document_command (comname, from_tty)
+ char *comname;
+ int from_tty;
+{
+ register struct cmd_list_element *c;
+ register char *p;
+ register char *cp;
+ register char *doc = 0;
+ register int len;
+ char *tmp = comname;
+
+ validate_comname (comname);
+ c = lookup_cmd (&tmp, cmdlist, "", 0, 1);
+ if (c->class != (int) class_user)
+ error ("Command \"%s\" is built-in.", comname);
+
+ if (from_tty)
+ printf ("Type documentation for \"%s\". \
+End with a line saying just \"end\".\n", comname);
+
+ while (p = read_one_command_line(from_tty? "> " : 0, from_tty))
+ {
+ if (strcmp(p, "end") == 0)
+ break;
+ len = strlen(p) + 1;
+ if (! doc)
+ {
+ doc = xmalloc(len);
+ cp = doc;
+ }
+ else
+ {
+ int i = cp - doc;
+ doc = xrealloc(doc, i + len);
+ cp = doc + i;
+ }
+ strcpy(cp, p);
+ cp += len;
+ cp[-1] = '\n';
+ }
+ if (doc && cp > doc)
+ cp[-1] = 0;
+ if (c->doc)
+ free (c->doc);
+ c->doc = doc;
+}
+
+static void
+print_gdb_version ()
+{
+ printf ("GDB %s, Copyright (C) 1989 Free Software Foundation, Inc.\n\
+There is ABSOLUTELY NO WARRANTY for GDB; type \"info warranty\" for details.\n\
+GDB is free software and you are welcome to distribute copies of it\n\
+ under certain conditions; type \"info copying\" to see the conditions.\n",
+ version);
+}
+
+static void
+version_info ()
+{
+ immediate_quit++;
+ print_gdb_version ();
+ immediate_quit--;
+}
+
+
+/* Command to specify a prompt string instead of "(gdb) ". */
+
+void
+set_prompt_command (text)
+ char *text;
+{
+ char *p, *q;
+ register int c;
+ char *new;
+
+ if (text == 0)
+ error_no_arg ("string to which to set prompt");
+
+ new = (char *) xmalloc (strlen (text) + 2);
+ p = text; q = new;
+ while (c = *p++)
+ {
+ if (c == '\\')
+ {
+ /* \ at end of argument is used after spaces
+ so they won't be lost. */
+ if (*p == 0)
+ break;
+ c = parse_escape (&p);
+ if (c == 0)
+ break; /* C loses */
+ else if (c > 0)
+ *q++ = c;
+ }
+ else
+ *q++ = c;
+ }
+ if (*(p - 1) != '\\')
+ *q++ = ' ';
+ *q++ = '\0';
+ new = (char *) xrealloc (new, q - new);
+ free (prompt);
+ prompt = new;
+}
+
+static void
+quit_command ()
+{
+ extern void exec_file_command ();
+ if (have_inferior_p ())
+ {
+ if (inhibit_confirm || query ("The program is running. Quit anyway? "))
+ {
+ /* Prevent any warning message from reopen_exec_file, in case
+ we have a core file that's inconsistent with the exec file. */
+ exec_file_command (0, 0);
+ kill_inferior ();
+ }
+ else
+ error ("Not confirmed.");
+ }
+ /* Save the history information if it is appropriate to do so. */
+ if (write_history_p && history_filename)
+ write_history (history_filename);
+ exit (0);
+}
+
+int
+input_from_terminal_p ()
+{
+ return instream == stdin;
+}
+
+static void
+pwd_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (arg) error ("The \"pwd\" command does not take an argument: %s", arg);
+ getwd (dirbuf);
+
+ if (strcmp (dirbuf, current_directory))
+ printf ("Working directory %s\n (canonically %s).\n",
+ current_directory, dirbuf);
+ else
+ printf ("Working directory %s.\n", current_directory);
+}
+
+static void
+cd_command (dir, from_tty)
+ char *dir;
+ int from_tty;
+{
+ int len;
+ int change;
+
+ if (dir == 0)
+ error_no_arg ("new working directory");
+
+ dir = tilde_expand (dir);
+ make_cleanup (free, dir);
+
+ len = strlen (dir);
+ dir = savestring (dir, len - (len > 1 && dir[len-1] == '/'));
+ if (dir[0] == '/')
+ current_directory = dir;
+ else
+ {
+ current_directory = concat (current_directory, "/", dir);
+ free (dir);
+ }
+
+ /* Now simplify any occurrences of `.' and `..' in the pathname. */
+
+ change = 1;
+ while (change)
+ {
+ char *p;
+ change = 0;
+
+ for (p = current_directory; *p;)
+ {
+ if (!strncmp (p, "/./", 2)
+ && (p[2] == 0 || p[2] == '/'))
+ strcpy (p, p + 2);
+ else if (!strncmp (p, "/..", 3)
+ && (p[3] == 0 || p[3] == '/')
+ && p != current_directory)
+ {
+ char *q = p;
+ while (q != current_directory && q[-1] != '/') q--;
+ if (q != current_directory)
+ {
+ strcpy (q-1, p+3);
+ p = q-1;
+ }
+ }
+ else p++;
+ }
+ }
+
+ if (chdir (dir) < 0)
+ perror_with_name (dir);
+
+ if (from_tty)
+ pwd_command ((char *) 0, 1);
+}
+
+static void
+source_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ FILE *stream;
+ struct cleanup *cleanups;
+ char *file = arg;
+ char *path;
+
+ if (file == 0)
+ /* Let source without arguments read .gdbinit. */
+ file = ".gdbinit";
+
+ file = tilde_expand (file);
+ make_cleanup (free, file);
+
+#ifdef KERNELDEBUG
+ if (path = getenv(kernel_debugging? "KGDBPATH" : "GDBPATH"))
+#else
+ if (path = getenv("GDBPATH"))
+#endif
+ {
+ int fd = openp(path, 1, file, O_RDONLY, 0, 0);
+
+ if (fd == -1)
+ stream = 0;
+ else
+ stream = fdopen(fd, "r");
+ }
+ else
+ stream = fopen (file, "r");
+
+ if (stream == 0)
+ perror_with_name (file);
+
+ cleanups = make_cleanup (source_cleanup, instream);
+
+ instream = stream;
+
+ command_loop ();
+
+ do_cleanups (cleanups);
+}
+
+static void
+echo_command (text)
+ char *text;
+{
+ char *p = text;
+ register int c;
+
+ if (text)
+ while (c = *p++)
+ {
+ 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)
+ fputc (c, stdout);
+ }
+ else
+ fputc (c, stdout);
+ }
+ fflush(stdout);
+}
+
+static void
+dump_me_command ()
+{
+ if (query ("Should GDB dump core? "))
+ {
+ signal (SIGQUIT, SIG_DFL);
+ kill (getpid (), SIGQUIT);
+ }
+}
+
+int
+parse_binary_operation (caller, arg)
+ char *caller, *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 ("\"%s\" not given a binary valued argument.", caller);
+}
+
+/* Functions to manipulate command line editing control variables. */
+
+static void
+set_editing (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ command_editing_p = parse_binary_operation ("set command-editing", arg);
+}
+
+/* Number of commands to print in each call to editing_info. */
+#define Hist_print 10
+static void
+editing_info (arg, from_tty)
+ char *arg;
+ 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;
+
+ struct _hist_entry {
+ char *line;
+ char *data;
+ } *history_get();
+ extern int history_base;
+
+ printf_filtered ("Interactive command editing is %s.\n",
+ command_editing_p ? "on" : "off");
+
+ printf_filtered ("History expansion of command input is %s.\n",
+ history_expansion_p ? "on" : "off");
+ printf_filtered ("Writing of a history record upon exit is %s.\n",
+ write_history_p ? "enabled" : "disabled");
+ printf_filtered ("The size of the history list (number of stored commands) is %d.\n",
+ history_size);
+ printf_filtered ("The name of the history record is \"%s\".\n\n",
+ history_filename ? history_filename : "");
+
+ /* 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 (arg)
+ {
+ if (arg[0] == '+' && arg[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 (arg) - history_base) - Hist_print / 2;
+ }
+ /* "info editing" 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;
+ }
+
+ if (num == hist_len - Hist_print)
+ printf_filtered ("The list of the last %d commands is:\n\n", Hist_print);
+ else
+ printf_filtered ("Some of the stored commands are:\n\n");
+
+ 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
+ "info editing +" does. This is unnecessary if arg is null,
+ because "info editing +" is not useful after "info editing". */
+ if (from_tty && arg)
+ {
+ arg[0] = '+';
+ arg[1] = '\0';
+ }
+}
+
+static void
+set_history_expansion (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ history_expansion_p = parse_binary_operation ("set history expansion", arg);
+}
+
+static void
+set_history_write (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ write_history_p = parse_binary_operation ("set history write", arg);
+}
+
+static void
+set_history (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf ("\"set history\" must be followed by the name of a history subcommand.\n");
+ help_list (sethistlist, "set history ", -1, stdout);
+}
+
+static void
+set_history_size (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (!*arg)
+ error_no_arg ("set history size");
+
+ history_size = atoi (arg);
+}
+
+static void
+set_history_filename (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ int i;
+
+ if (!arg)
+ error_no_arg ("history file name");
+
+ arg = tilde_expand (arg);
+ make_cleanup (free, arg);
+
+ i = strlen (arg) - 1;
+
+ free (history_filename);
+
+ while (i > 0 && (arg[i] == ' ' || arg[i] == '\t'))
+ i--;
+ ++i;
+
+ if (!*arg)
+ history_filename = (char *) 0;
+ else
+ history_filename = savestring (arg, i + 1);
+ history_filename[i] = '\0';
+}
+
+int info_verbose;
+
+static void
+set_verbose_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ info_verbose = parse_binary_operation ("set verbose", arg);
+}
+
+static void
+verbose_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (arg)
+ error ("\"info verbose\" does not take any arguments.\n");
+
+ printf ("Verbose printing of information is %s.\n",
+ info_verbose ? "on" : "off");
+}
+
+static void
+float_handler ()
+{
+ error ("Invalid floating value encountered or computed.");
+}
+
+
+static void
+initialize_cmd_lists ()
+{
+ cmdlist = (struct cmd_list_element *) 0;
+ infolist = (struct cmd_list_element *) 0;
+ enablelist = (struct cmd_list_element *) 0;
+ disablelist = (struct cmd_list_element *) 0;
+ deletelist = (struct cmd_list_element *) 0;
+ enablebreaklist = (struct cmd_list_element *) 0;
+ setlist = (struct cmd_list_element *) 0;
+ sethistlist = (struct cmd_list_element *) 0;
+ unsethistlist = (struct cmd_list_element *) 0;
+}
+
+static void
+initialize_main ()
+{
+ char *tmpenv;
+ /* Command line editing externals. */
+ extern int (*rl_completion_entry_function)();
+ extern char *rl_completer_word_break_characters;
+ extern char *rl_readline_name;
+
+ /* Set default verbose mode on. */
+ info_verbose = 1;
+
+#ifdef KERNELDEBUG
+ if (kernel_debugging)
+ prompt = savestring ("(kgdb) ", 7);
+ else
+#endif
+ prompt = savestring ("(gdb) ", 6);
+
+ /* Set the important stuff up for command editing. */
+ command_editing_p = 1;
+ history_expansion_p = 0;
+ write_history_p = 0;
+
+ if (tmpenv = getenv ("HISTSIZE"))
+ history_size = atoi (tmpenv);
+ else
+ history_size = 256;
+
+ stifle_history (history_size);
+
+ if (tmpenv = getenv ("GDBHISTFILE"))
+ history_filename = savestring (tmpenv, strlen(tmpenv));
+ else
+ /* 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", "");
+
+ read_history (history_filename);
+
+ /* 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_readline_name = "gdb";
+
+ /* Define the classes of commands.
+ They will appear in the help list in the reverse of this order. */
+
+ add_cmd ("obscure", class_obscure, 0, "Obscure features.", &cmdlist);
+ add_cmd ("alias", class_alias, 0, "Aliases of other commands.", &cmdlist);
+ add_cmd ("user", class_user, 0, "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, 0, "Support facilities.", &cmdlist);
+ add_cmd ("status", class_info, 0, "Status inquiries.", &cmdlist);
+ add_cmd ("files", class_files, 0, "Specifying and examining files.", &cmdlist);
+ add_cmd ("breakpoints", class_breakpoint, 0, "Making program stop at certain points.", &cmdlist);
+ add_cmd ("data", class_vars, 0, "Examining data.", &cmdlist);
+ add_cmd ("stack", class_stack, 0, "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, 0, "Running the program.", &cmdlist);
+
+ add_com ("pwd", class_files, pwd_command,
+ "Print working directory. This is used for your program as well.");
+ add_com ("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.");
+
+ add_cmd ("prompt", class_support, set_prompt_command,
+ "Change gdb's prompt from the default of \"(gdb)\"",
+ &setlist);
+ 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.");
+
+ add_com ("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.");
+ 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);
+ add_com ("while", class_support, while_command,
+ "execute following commands while condition is true.\n\
+Expression for condition follows \"while\" keyword.");
+ add_com ("if", class_support, if_command,
+ "execute following commands if condition is true.\n\
+Expression for condition follows \"if\" keyword.");
+ add_cmd ("verbose", class_support, set_verbose_command,
+ "Change the number of informational messages gdb prints.",
+ &setlist);
+ add_info ("verbose", verbose_info,
+ "Status of gdb's verbose printing option.\n");
+
+ add_com ("dump-me", class_obscure, dump_me_command,
+ "Get fatal error; make debugger dump its core.");
+
+ add_cmd ("editing", class_support, set_editing,
+ "Enable or disable command line editing.\n\
+Use \"on\" to enable to enable the editing, and \"off\" to disable it.\n\
+Without an argument, command line editing is enabled.", &setlist);
+
+ add_prefix_cmd ("history", class_support, set_history,
+ "Generic command for setting command history parameters.",
+ &sethistlist, "set history ", 0, &setlist);
+
+ add_cmd ("expansion", no_class, set_history_expansion,
+ "Enable or disable history expansion on command input.\n\
+Without an argument, history expansion is enabled.", &sethistlist);
+
+ add_cmd ("write", no_class, set_history_write,
+ "Enable or disable 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);
+
+ add_cmd ("size", no_class, set_history_size,
+ "Set the size of the command history, \n\
+ie. the number of previous commands to keep a record of.", &sethistlist);
+
+ add_cmd ("filename", no_class, set_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);
+
+ add_prefix_cmd ("info", class_info, info_command,
+ "Generic command for printing status.",
+ &infolist, "info ", 0, &cmdlist);
+ add_com_alias ("i", "info", class_info, 1);
+
+ add_info ("editing", editing_info, "Status of command editor.");
+
+ add_info ("version", version_info, "Report what version of GDB this is.");
+}
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..338400f
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/README.FreeBSD
@@ -0,0 +1,7 @@
+This is a greatly pared down libmmalloc directory. Only what's required to build
+gdb-4.12 on FreeBSD was kept.
+
+This is temporary. In FreeBSD 2.0 a fully ported libmmalloc will likely appear
+as a system library for use by all the build tools.
+
+paul@freefall.cdrom.com
diff --git a/gnu/usr.bin/gdb/mmalloc/attach.c b/gnu/usr.bin/gdb/mmalloc/attach.c
new file mode 100644
index 0000000..6737fca
--- /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..03d632c
--- /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..69d41b9
--- /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..aee43aa
--- /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..46b450e
--- /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..54b6ed6
--- /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..73368a1
--- /dev/null
+++ b/gnu/usr.bin/gdb/mmalloc/mmtrace.c
@@ -0,0 +1,166 @@
+/* More debugging hooks for `mmalloc'.
+ Copyright 1991, 1992 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, "- %08x\n", (unsigned int) 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, "+ %08x %x\n", (unsigned int) 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, "! %08x %x\n", (unsigned int) ptr, size);
+ else
+ fprintf (mallstream, "< %08x\n> %08x %x\n", (unsigned int) ptr,
+ (unsigned int) 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/gdb/ngdb.i386/Makefile b/gnu/usr.bin/gdb/ngdb.i386/Makefile
new file mode 100644
index 0000000..3bf4c6c
--- /dev/null
+++ b/gnu/usr.bin/gdb/ngdb.i386/Makefile
@@ -0,0 +1,27 @@
+# %W% (Berkeley) %G%
+
+.include "../config/Makefile.$(MACHINE)"
+
+PROG= ngdb
+SRCS= i386bsd-dep.c blockframe.c
+GDBOBJS+= i386-pinsn.o \
+ breakpoint.o command.o copying.o core.o \
+ cplus-dem.o dbxread.o environ.o eval.o expprint.o \
+ expread.o findvar.o infcmd.o inflow.o infrun.o \
+ main.o obstack.o printcmd.o regex.o remote.o \
+ remote-sl.o source.o stack.o symmisc.o symtab.o \
+ utils.o valarith.o valops.o valprint.o values.o \
+ version.o \
+ funmap.o history.o keymaps.o readline.o \
+ init.o
+CFLAGS+= -g -I$(.CURDIR) -I.. -I$(.CURDIR)/.. -I$(.CURDIR)/../config \
+ -I/usr/src/sys.newvm \
+ -DNEWVM -DHAVE_VPRINTF -DVI_MODE -DKERNELDEBUG
+# CC= /usr/old/bin/cc
+# CC= cc -traditional
+LDADD+= $(GDBOBJS:S/^/..\//g) -ltermcap
+NOMAN= noman
+
+.PATH: $(.CURDIR)/../config $(.CURDIR)/..
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/gdb/obstack.c b/gnu/usr.bin/gdb/obstack.c
new file mode 100644
index 0000000..6f4b282
--- /dev/null
+++ b/gnu/usr.bin/gdb/obstack.c
@@ -0,0 +1,313 @@
+/* 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 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+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 "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.
+ Pick a number small enough that when rounded up to DEFAULT_ROUNDING
+ it is still smaller than 4096 - 4. */
+ {
+ int extra = 4;
+ if (extra < DEFAULT_ROUNDING)
+ extra = DEFAULT_ROUNDING;
+ 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;
+}
+
+/* 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;
+
+ /* Compute size for new chunk. */
+ new_size = (obj_size + length) << 1;
+ 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 because these
+ structures are aligned at least that much. */
+ for (i = (obj_size + sizeof (COPYING_UNIT) - 1) / sizeof (COPYING_UNIT) - 1;
+ i >= 0; i--)
+ ((COPYING_UNIT *)new_chunk->contents)[i]
+ = ((COPYING_UNIT *)h->object_base)[i];
+
+ h->object_base = new_chunk->contents;
+ h->next_free = h->object_base + obj_size;
+}
+
+/* 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;
+ 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. */
+
+void
+#ifdef __STDC__
+#undef obstack_free
+obstack_free (struct obstack *h, POINTER obj)
+#else
+_obstack_free (h, obj)
+ struct obstack *h;
+ POINTER obj;
+#endif
+{
+ 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;
+ while (lp != 0 && ((POINTER)lp > obj || (POINTER)(lp)->limit < obj))
+ {
+ plp = lp -> prev;
+ (*h->freefun) (lp);
+ lp = plp;
+ }
+ 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 ();
+}
+
+/* Let same .o link with output of gcc and other compilers. */
+
+#ifdef __STDC__
+void
+_obstack_free (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ obstack_free (h, obj);
+}
+#endif
+
+#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/gdb/obstack.h b/gnu/usr.bin/gdb/obstack.h
new file mode 100644
index 0000000..27c017e
--- /dev/null
+++ b/gnu/usr.bin/gdb/obstack.h
@@ -0,0 +1,372 @@
+/* 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 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+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! */
+
+
+/* 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 "facist 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 aymbol 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 beggining of the new larger chunk. We then carry on
+accreting characters to the end of the object as we normaly 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. */
+};
+
+#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_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_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, obstack_chunk_alloc, obstack_chunk_free)
+
+#define obstack_begin(h, size) \
+ _obstack_begin ((h), (size), 0, obstack_chunk_alloc, 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__)
+
+/* 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) \
+ ({ struct obstack *__o = (OBSTACK); \
+ (unsigned) (__o->next_free - __o->object_base); })
+
+#define obstack_room(OBSTACK) \
+ ({ struct obstack *__o = (OBSTACK); \
+ (unsigned) (__o->chunk_limit - __o->next_free); })
+
+#define obstack_grow(OBSTACK,where,length) \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ ((__o->next_free + __len > __o->chunk_limit) \
+ ? _obstack_newchunk (__o, __len) : 0); \
+ bcopy (where, __o->next_free, __len); \
+ __o->next_free += __len; \
+ (void) 0; })
+
+#define obstack_grow0(OBSTACK,where,length) \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ ((__o->next_free + __len + 1 > __o->chunk_limit) \
+ ? _obstack_newchunk (__o, __len + 1) : 0), \
+ bcopy (where, __o->next_free, __len), \
+ __o->next_free += __len, \
+ *(__o->next_free)++ = 0; \
+ (void) 0; })
+
+#define obstack_1grow(OBSTACK,datum) \
+({ struct obstack *__o = (OBSTACK); \
+ ((__o->next_free + 1 > __o->chunk_limit) \
+ ? _obstack_newchunk (__o, 1) : 0), \
+ *(__o->next_free)++ = (datum); \
+ (void) 0; })
+
+#define obstack_blank(OBSTACK,length) \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ ((__o->next_free + __len > __o->chunk_limit) \
+ ? _obstack_newchunk (__o, __len) : 0); \
+ __o->next_free += __len; \
+ (void) 0; })
+
+#define obstack_alloc(OBSTACK,length) \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_blank (__h, (length)); \
+ obstack_finish (__h); })
+
+#define obstack_copy(OBSTACK,where,length) \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+#define obstack_copy0(OBSTACK,where,length) \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow0 (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+#define obstack_finish(OBSTACK) \
+({ struct obstack *__o = (OBSTACK); \
+ void *value = (void *) __o->object_base; \
+ __o->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT (__o->next_free)+__o->alignment_mask)\
+ & ~ (__o->alignment_mask)); \
+ ((__o->next_free - (char *)__o->chunk \
+ > __o->chunk_limit - (char *)__o->chunk) \
+ ? (__o->next_free = __o->chunk_limit) : 0); \
+ __o->object_base = __o->next_free; \
+ value; })
+
+#define obstack_free(OBSTACK, OBJ) \
+({ 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__ */
+
+/* The non-GNU macros copy the obstack-pointer into this global variable
+ to avoid multiple evaluation. */
+
+extern struct obstack *_obstack;
+
+#define obstack_object_size(h) \
+ (unsigned) (_obstack = (h), (h)->next_free - (h)->object_base)
+
+#define obstack_room(h) \
+ (unsigned) (_obstack = (h), (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), \
+ 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), \
+ 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), \
+ *((h)->next_free)++ = (datum))
+
+#define obstack_blank(h,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp > (h)->chunk_limit) \
+ ? _obstack_newchunk ((h), (h)->temp) : 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)->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)))
+#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) \
+ : (int) _obstack_free ((h), (h)->temp + (char *) (h)->chunk)))
+#endif
+
+#endif /* not __GNUC__ or not __STDC__ */
+
+#endif /* not __OBSTACKS__ */
+
diff --git a/gnu/usr.bin/gdb/printcmd.c b/gnu/usr.bin/gdb/printcmd.c
new file mode 100644
index 0000000..6edd7bd
--- /dev/null
+++ b/gnu/usr.bin/gdb/printcmd.c
@@ -0,0 +1,1867 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)printcmd.c 6.5 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Print values for GNU debugger GDB.
+ Copyright (C) 1986, 1987, 1988, 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. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "symtab.h"
+#include "value.h"
+#include "expression.h"
+
+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 last_examine_value;
+
+/* Number of auto-display expression currently being displayed.
+ So that we can deleted it if we get an error or a signal within it.
+ -1 when not doing one. */
+
+int current_display_number;
+
+static void do_one_display ();
+
+void do_displays ();
+void print_address ();
+void print_floating ();
+void print_scalar_formatted ();
+void print_formatted_address ();
+
+
+/* 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. */
+
+struct format_data
+decode_format (string_ptr, oformat, osize)
+ char **string_ptr;
+ char oformat;
+ char 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++;
+#ifdef LONG_LONG
+ else if (*p == 'l')
+ {
+ val.size = 'g';
+ p++;
+ }
+#endif
+ else if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z'))
+ val.format = *p++;
+ else
+ break;
+ }
+
+#ifndef LONG_LONG
+ /* Make sure 'g' size is not used on integer types.
+ Well, actually, we can handle hex. */
+ if (val.size == 'g' && val.format != 'f' && val.format != 'x')
+ val.size = 'w';
+#endif
+
+ 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':
+ case 'A':
+ /* Addresses must be words. */
+ val.size = osize ? 'w' : osize;
+ 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 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 val;
+ register char format;
+ char 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), stdout, 0, Val_pretty_default);
+ break;
+
+ case 'i':
+ next_address = VALUE_ADDRESS (val)
+ + print_insn (VALUE_ADDRESS (val), stdout);
+ break;
+
+ default:
+ if (format == 0
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_ARRAY
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_UNION
+ || VALUE_REPEATED (val))
+ value_print (val, stdout, format, Val_pretty_default);
+ else
+ print_scalar_formatted (VALUE_CONTENTS (val), VALUE_TYPE (val),
+ format, size, 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;
+ char format;
+ int size;
+ FILE *stream;
+{
+ LONGEST val_long;
+ int len = TYPE_LENGTH (type);
+
+ if (size == 'g' && sizeof (LONGEST) < 8
+ && format == 'x')
+ {
+ /* ok, we're going to have to get fancy here. Assumption: a
+ long is four bytes. */
+ unsigned long v1, v2, tmp;
+
+ v1 = unpack_long (builtin_type_long, valaddr);
+ v2 = unpack_long (builtin_type_long, valaddr + 4);
+
+#ifdef BYTES_BIG_ENDIAN
+#else
+ /* Little endian -- swap the two for printing */
+ tmp = v1;
+ v1 = v2;
+ v2 = tmp;
+#endif
+
+ switch (format)
+ {
+ case 'x':
+ fprintf_filtered (stream, "0x%08x%08x", v1, v2);
+ break;
+ default:
+ error ("Output size \"g\" unimplemented for format \"%c\".",
+ format);
+ }
+ return;
+ }
+
+ val_long = unpack_long (type, valaddr);
+
+ /* If value is unsigned, truncate it in case negative. */
+ if (format != 'd')
+ {
+ if (len == sizeof (char))
+ val_long &= (1 << 8 * sizeof(char)) - 1;
+ else if (len == sizeof (short))
+ val_long &= (1 << 8 * sizeof(short)) - 1;
+ else if (len == sizeof (long))
+ val_long &= (unsigned long) - 1;
+ }
+
+ switch (format)
+ {
+ case 'x':
+#ifdef LONG_LONG
+ if (!size)
+ size = (len < sizeof (long long) ? 'w' : 'g');
+ switch (size)
+ {
+ case 'b':
+ fprintf_filtered (stream, "0x%02llx", val_long);
+ break;
+ case 'h':
+ fprintf_filtered (stream, "0x%04llx", val_long);
+ break;
+ case 0: /* no size specified, like in print */
+ case 'w':
+ fprintf_filtered (stream, "0x%08llx", val_long);
+ break;
+ case 'g':
+ fprintf_filtered (stream, "0x%016llx", val_long);
+ break;
+ default:
+ error ("Undefined output size \"%c\".", size);
+ }
+#else
+ switch (size)
+ {
+ case 'b':
+ fprintf_filtered (stream, "0x%02x", val_long);
+ break;
+ case 'h':
+ fprintf_filtered (stream, "0x%04x", val_long);
+ break;
+ case 0: /* no size specified, like in print */
+ case 'w':
+ fprintf_filtered (stream, "0x%08x", val_long);
+ break;
+ case 'g':
+ fprintf_filtered (stream, "0x%o16x", val_long);
+ break;
+ default:
+ error ("Undefined output size \"%c\".", size);
+ }
+#endif /* not LONG_LONG */
+ break;
+
+ case 'd':
+#ifdef LONG_LONG
+ fprintf_filtered (stream, "%lld", val_long);
+#else
+ fprintf_filtered (stream, "%d", val_long);
+#endif
+ break;
+
+ case 'u':
+#ifdef LONG_LONG
+ fprintf_filtered (stream, "%llu", val_long);
+#else
+ fprintf_filtered (stream, "%u", val_long);
+#endif
+ break;
+
+ case 'o':
+ if (val_long)
+#ifdef LONG_LONG
+ fprintf_filtered (stream, "0%llo", val_long);
+#else
+ fprintf_filtered (stream, "0%o", val_long);
+#endif
+ else
+ fprintf_filtered (stream, "0");
+ break;
+
+ case 'a':
+ print_address ((CORE_ADDR) val_long, stream);
+ break;
+
+ case 'A':
+ print_formatted_address ((CORE_ADDR) val_long, stream);
+ break;
+
+ case 'c':
+ value_print (value_from_long (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 ();
+
+ default:
+ error ("Undefined output format \"%c\".", format);
+ }
+}
+
+/* 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;
+ FILE *stream;
+{
+ double doub;
+ int inv;
+ int len = TYPE_LENGTH (type);
+
+ doub = unpack_double (type, valaddr, &inv);
+ if (inv)
+ fprintf_filtered (stream, "Invalid float value");
+ else if (doub != doub)
+ {
+ /* Surely it is an IEEE floating point NaN. */
+
+ long low, high, *arg = (long *)valaddr; /* ASSUMED 32 BITS */
+ int nonneg;
+
+ if (len <= sizeof(float))
+ {
+ /* It's single precision. */
+ low = *arg;
+ nonneg = low >= 0;
+ low &= 0x7fffff;
+ high = 0;
+ }
+ else
+ {
+ /* It's double precision.
+ Get the high and low words of the fraction.
+ Distinguish big and little-endian machines. */
+#ifdef WORDS_BIG_ENDIAN
+ low = arg[1], high = arg[0];
+#else
+ low = arg[0], high = arg[1];
+#endif
+ nonneg = high >= 0;
+ high &= 0xfffff;
+ }
+ if (high)
+ fprintf_filtered (stream, "-NaN(0x%lx%.8lx)" + nonneg, high, low);
+ else
+ fprintf_filtered (stream, "-NaN(0x%lx)" + nonneg, low);
+ }
+ else
+ fprintf_filtered (stream, len <= sizeof(float) ? "%.6g" : "%.17g", doub);
+}
+
+/* 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_long (builtin_type_int, (LONGEST) addr));
+}
+
+/* Optionally print address ADDR symbolically as <SYMBOL+OFFSET> on STREAM. */
+
+void
+print_address_symbolic (addr, stream)
+ CORE_ADDR addr;
+ FILE *stream;
+{
+ register char *format;
+ int name_location;
+ register int i = find_pc_misc_function (addr);
+
+ /* If nothing comes out, don't print anything symbolic. */
+ if (i < 0) return;
+ name_location = misc_function_vector[i].address;
+
+ if (addr - name_location)
+ format = " <%s+%d>";
+ else
+ format = " <%s>";
+
+ fprintf_filtered (stream, format,
+ misc_function_vector[i].name, addr - name_location);
+}
+
+/* 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;
+ FILE *stream;
+{
+ fprintf_filtered (stream, "0x%x", addr);
+ print_address_symbolic (addr, stream);
+}
+
+/* Like print_address but opnly prints symbolically. */
+
+void
+print_formatted_address (addr, stream)
+ CORE_ADDR addr;
+ FILE *stream;
+{
+ register int i = 0;
+ register char *format;
+ register struct symbol *fs;
+ char *name;
+ int name_location;
+
+ i = find_pc_partial_function (addr, &name, &name_location);
+
+ /* If nothing comes out, don't print anything symbolic. */
+
+ if (i == 0)
+ fprintf_filtered (stream, "0x%x", addr);
+ else if (addr - name_location)
+ fprintf_filtered (stream, "%s+%d", name, addr - name_location);
+ else
+ fprintf_filtered (stream, "%s", name);
+}
+
+/* Examine data at address ADDR in format FMT.
+ Fetch it from memory and print on 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;
+ 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 = builtin_type_char;
+ else if (size == 'h')
+ val_type = builtin_type_short;
+ else if (size == 'w')
+ val_type = builtin_type_long;
+ else if (size == 'g')
+#ifndef LONG_LONG
+ val_type = builtin_type_double;
+#else
+ val_type = builtin_type_long_long;
+#endif
+
+ 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, 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");
+ fflush (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);
+}
+
+static void
+print_command (exp)
+ char *exp;
+{
+ struct expression *expr;
+ register struct cleanup *old_chain = 0;
+ register char format = 0;
+ register value val;
+ struct format_data fmt;
+ int histindex;
+ int cleanup = 0;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, last_format, 0);
+ validate_format (fmt, "print");
+ last_format = format = fmt.format;
+ }
+
+ if (exp && *exp)
+ {
+ expr = parse_c_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ cleanup = 1;
+ val = evaluate_expression (expr);
+ }
+ else
+ val = access_value_history (0);
+
+ histindex = record_latest_value (val);
+ if (histindex >= 0) printf_filtered ("$%d = ", histindex);
+
+ print_formatted (val, format, fmt.size);
+ printf_filtered ("\n");
+
+ if (cleanup)
+ do_cleanups (old_chain);
+}
+
+static void
+output_command (exp)
+ char *exp;
+{
+ struct expression *expr;
+ register struct cleanup *old_chain;
+ register char format = 0;
+ register value val;
+ struct format_data fmt;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, 0, 0);
+ validate_format (fmt, "print");
+ format = fmt.format;
+ }
+
+ expr = parse_c_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+
+ val = evaluate_expression (expr);
+
+ print_formatted (val, format, fmt.size);
+
+ do_cleanups (old_chain);
+}
+
+static void
+set_command (exp)
+ char *exp;
+{
+ struct expression *expr = parse_c_expression (exp);
+ register struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &expr);
+ evaluate_expression (expr);
+ do_cleanups (old_chain);
+}
+
+static void
+address_info (exp)
+ char *exp;
+{
+ register struct symbol *sym;
+ register CORE_ADDR val;
+ 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);
+ if (sym == 0)
+ {
+ register int i;
+
+ if (is_a_field_of_this)
+ {
+ printf ("Symbol \"%s\" is a field of the local class variable `this'\n", exp);
+ return;
+ }
+
+ for (i = 0; i < misc_function_count; i++)
+ if (!strcmp (misc_function_vector[i].name, exp))
+ break;
+
+ if (i < misc_function_count)
+ printf ("Symbol \"%s\" is at 0x%x in a file compiled without -g.\n",
+ exp, misc_function_vector[i].address);
+ else
+ error ("No symbol \"%s\" in current context.", exp);
+ return;
+ }
+
+ printf ("Symbol \"%s\" is ", SYMBOL_NAME (sym));
+ val = SYMBOL_VALUE (sym);
+
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_CONST:
+ case LOC_CONST_BYTES:
+ printf ("constant");
+ break;
+
+ case LOC_LABEL:
+ printf ("a label at address 0x%x", val);
+ break;
+
+ case LOC_REGISTER:
+ printf ("a variable in register %s", reg_names[val]);
+ break;
+
+ case LOC_STATIC:
+ printf ("static at address 0x%x", val);
+ break;
+
+ case LOC_REGPARM:
+ printf ("an argument in register %s", reg_names[val]);
+ break;
+
+ case LOC_ARG:
+ printf ("an argument at offset %d", val);
+ break;
+
+ case LOC_LOCAL:
+ printf ("a local variable at frame offset %d", val);
+ break;
+
+ case LOC_REF_ARG:
+ printf ("a reference argument at offset %d", val);
+ break;
+
+ case LOC_TYPEDEF:
+ printf ("a typedef");
+ break;
+
+ case LOC_BLOCK:
+ printf ("a function at address 0x%x",
+ BLOCK_START (SYMBOL_BLOCK_VALUE (sym)));
+ break;
+ }
+ printf (".\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);
+ last_size = fmt.size;
+ last_format = fmt.format;
+ }
+
+ /* If we have an expression, evaluate it and use it as the address. */
+
+ if (exp != 0 && *exp != 0)
+ {
+ expr = parse_c_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);
+ /* 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 = (CORE_ADDR) value_as_long (val);
+ do_cleanups (old_chain);
+ }
+
+ do_examine (fmt, next_address);
+
+ /* Set a couple of internal variables if appropriate. */
+ if (last_examine_value)
+ {
+ /* Make last address examined available to the user as $_. */
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_long (builtin_type_int,
+ (LONGEST) last_examine_address));
+
+ /* Make contents of last address examined available to the user as $__.*/
+ set_internalvar (lookup_internalvar ("__"), last_examine_value);
+ }
+}
+
+/* Commands for printing types of things. */
+
+static void
+whatis_command (exp)
+ char *exp;
+{
+ struct expression *expr;
+ register value val;
+ register struct cleanup *old_chain;
+
+ if (exp)
+ {
+ expr = parse_c_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ val = evaluate_type (expr);
+ }
+ else
+ val = access_value_history (0);
+
+ printf_filtered ("type = ");
+ /* 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. */
+ type_print (VALUE_TYPE (val), "", stdout, -1);
+ printf_filtered ("\n");
+
+ if (exp)
+ do_cleanups (old_chain);
+}
+
+static void
+ptype_command (typename)
+ char *typename;
+{
+ register char *p = typename;
+ register int len;
+ extern struct block *get_current_block ();
+ register struct block *b
+ = (have_inferior_p () || have_core_file_p ()) ? get_current_block () : 0;
+ register struct type *type;
+
+ if (typename == 0)
+ error_no_arg ("type name");
+
+ while (*p && *p != ' ' && *p != '\t') p++;
+ len = p - typename;
+ while (*p == ' ' || *p == '\t') p++;
+
+ if (len == 6 && !strncmp (typename, "struct", 6))
+ type = lookup_struct (p, b);
+ else if (len == 5 && !strncmp (typename, "union", 5))
+ type = lookup_union (p, b);
+ else if (len == 4 && !strncmp (typename, "enum", 4))
+ type = lookup_enum (p, b);
+ else
+ {
+ type = lookup_typename (typename, b, 1);
+ if (type == 0)
+ {
+ register struct symbol *sym
+ = lookup_symbol (typename, b, STRUCT_NAMESPACE, 0);
+ if (sym == 0)
+ error ("No type named %s.", typename);
+ printf_filtered ("No type named %s, but there is a ",
+ typename);
+ switch (TYPE_CODE (SYMBOL_TYPE (sym)))
+ {
+ case TYPE_CODE_STRUCT:
+ printf_filtered ("struct");
+ break;
+
+ case TYPE_CODE_UNION:
+ printf_filtered ("union");
+ break;
+
+ case TYPE_CODE_ENUM:
+ printf_filtered ("enum");
+ }
+ printf_filtered (" %s. Type \"help ptype\".\n", typename);
+ type = SYMBOL_TYPE (sym);
+ }
+ }
+
+ type_print (type, "", stdout, 1);
+ printf_filtered ("\n");
+}
+
+enum display_status {disabled, enabled};
+
+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 display_status status;
+};
+
+/* Chain of expressions whose values should be displayed
+ automatically each time the program stops. */
+
+static struct display *display_chain;
+
+static int display_number;
+
+/* 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;
+ extern struct block *innermost_block;
+
+ 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_c_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 && have_inferior_p ())
+ do_one_display (new);
+
+ dont_repeat ();
+}
+
+static void
+free_display (d)
+ struct display *d;
+{
+ free (d->exp);
+ free (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)
+ {
+ free (d->exp);
+ display_chain = d->next;
+ free (d);
+ }
+}
+
+/* Delete the auto-display number NUM. */
+
+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)
+ char *args;
+{
+ register char *p = args;
+ register char *p1;
+ register int num;
+ register struct display *d, *d1;
+
+ 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;
+
+ printf_filtered ("%d: ", d->number);
+ if (d->format.size)
+ {
+ 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 (" ");
+ print_expression (d->exp, stdout);
+ if (d->format.count != 1)
+ printf_filtered ("\n");
+ else
+ printf_filtered (" ");
+ do_examine (d->format,
+ (CORE_ADDR) value_as_long (evaluate_expression (d->exp)));
+
+ }
+ else
+ {
+ if (d->format.format)
+ printf_filtered ("/%c ", d->format.format);
+ print_expression (d->exp, stdout);
+ printf_filtered (" = ");
+ print_formatted (evaluate_expression (d->exp),
+ d->format.format, d->format.size);
+ printf_filtered ("\n");
+ }
+
+ fflush (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 ("No display number %d.\n", num);
+}
+
+void
+disable_current_display ()
+{
+ if (current_display_number >= 0)
+ {
+ disable_display (current_display_number);
+ fprintf (stderr, "Disabling display %d to avoid infinite recursion.\n",
+ current_display_number);
+ }
+ current_display_number = -1;
+}
+
+static void
+display_info ()
+{
+ register struct display *d;
+
+ if (!display_chain)
+ printf ("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, stdout);
+ if (d->block && !contained_in (get_selected_block (), d->block))
+ printf_filtered (" (cannot be evaluated in the current context)");
+ printf_filtered ("\n");
+ fflush (stdout);
+ }
+}
+
+void
+enable_display (args)
+ char *args;
+{
+ 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 ("No display number %d.\n", num);
+ win:
+ p = p1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+}
+
+void
+disable_display_command (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 = disabled;
+ }
+ 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);
+
+ 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;
+ FILE *stream;
+{
+ value val = read_var_value (var, frame);
+ value_print (val, stream, 0, Val_pretty_default);
+}
+
+static int
+compare_ints (i, j)
+ int *i, *j;
+{
+ return *i - *j;
+}
+
+/* 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). */
+
+static void print_frame_nameless_args ();
+
+void
+print_frame_args (func, fi, num, stream)
+ struct symbol *func;
+ struct frame_info *fi;
+ int num;
+ FILE *stream;
+{
+ struct block *b;
+ int nsyms = 0;
+ int first = 1;
+ register int i;
+ register int last_regparm = 0;
+ register struct symbol *lastsym, *sym, *nextsym;
+ register value val;
+ /* Offset of stack argument that is at the highest offset.
+ -1 if we haven't come to a stack argument yet. */
+ CORE_ADDR highest_offset = (CORE_ADDR) -1;
+ register CORE_ADDR addr = FRAME_ARGS_ADDRESS (fi);
+
+ if (func)
+ {
+ b = SYMBOL_BLOCK_VALUE (func);
+ nsyms = BLOCK_NSYMS (b);
+ }
+
+ for (i = 0; i < nsyms; i++)
+ {
+ QUIT;
+ sym = BLOCK_SYM (b, i);
+
+ if (SYMBOL_CLASS (sym) != LOC_REGPARM
+ && SYMBOL_CLASS (sym) != LOC_ARG
+ && SYMBOL_CLASS (sym) != LOC_REF_ARG)
+ continue;
+
+ /* Print the next arg. */
+ if (SYMBOL_CLASS (sym) == LOC_REGPARM)
+ val = value_from_register (SYMBOL_TYPE (sym),
+ SYMBOL_VALUE (sym),
+ FRAME_INFO_ID (fi));
+ else
+ {
+ int current_offset = SYMBOL_VALUE (sym);
+ int arg_size = TYPE_LENGTH (SYMBOL_TYPE (sym));
+
+ if (SYMBOL_CLASS (sym) == LOC_REF_ARG)
+ val = value_at (SYMBOL_TYPE (sym),
+ read_memory_integer (addr + current_offset,
+ sizeof (CORE_ADDR)));
+ else
+ val = value_at (SYMBOL_TYPE (sym), addr + current_offset);
+
+ /* Round up address of next arg to multiple of size of int. */
+ current_offset
+ = (((current_offset + sizeof (int) - 1) / sizeof (int))
+ * sizeof (int));
+
+ /* If this is the highest offset seen yet, set highest_offset. */
+ if (highest_offset == (CORE_ADDR)-1
+ || ((current_offset
+ + (arg_size - sizeof (int) + 3) / (sizeof (int)))
+ > highest_offset))
+ highest_offset = current_offset;
+ }
+
+ if (! first)
+ fprintf_filtered (stream, ", ");
+ fputs_filtered (SYMBOL_NAME (sym), stream);
+ fputs_filtered ("=", stream);
+
+/* Nonzero if a LOC_ARG which is a struct is useless. */
+#if !defined (STRUCT_ARG_SYM_GARBAGE)
+#define STRUCT_ARG_SYM_GARBAGE(gcc_p) 0
+#endif
+
+ if (STRUCT_ARG_SYM_GARBAGE (b->gcc_compile_flag)
+ && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+ && SYMBOL_CLASS (sym) == LOC_ARG)
+ {
+ /* Try looking up that name. SunOS4 puts out a usable
+ symbol as a local variable (in addition to the one
+ for the arg). */
+ struct symbol *sym2 =
+ lookup_symbol (SYMBOL_NAME (sym), b, VAR_NAMESPACE, 0);
+
+ if (sym2 != NULL)
+ val = value_of_variable (sym2);
+ else
+ {
+ fputs_filtered ("?", stream);
+ first = 0;
+ continue;
+ }
+ }
+
+ value_print (val, stream, 0, Val_no_prettyprint);
+ first = 0;
+ }
+
+ /* Don't print nameless args in situations where we don't know
+ enough about the stack to find them. */
+ if (num != -1)
+ {
+ if (highest_offset != (CORE_ADDR) -1
+ && num * sizeof (int) + FRAME_ARGS_SKIP > highest_offset)
+ print_frame_nameless_args (fi, addr,
+ highest_offset + sizeof (int),
+ num * sizeof (int) + FRAME_ARGS_SKIP,
+ stream);
+ else
+ print_frame_nameless_args (fi, addr, FRAME_ARGS_SKIP,
+ num * sizeof (int) + FRAME_ARGS_SKIP,
+ stream);
+ }
+}
+
+static void
+print_frame_nameless_args (fi, argsaddr, start, end, stream)
+ struct frame_info *fi;
+ CORE_ADDR argsaddr;
+ int start;
+ int end;
+ FILE *stream;
+{
+ extern void (*default_scalar_print)();
+ LONGEST v;
+ int p = start;
+ char *s = "";
+
+ for (p = start; p < end; p += sizeof(int)) {
+ QUIT;
+#if defined(NAMELESS_ARG)
+ v = NAMELESS_ARG(fi, (p - start) / sizeof(int));
+#else
+ v = read_memory_integer (argsaddr + p, sizeof (int));
+#endif
+ fprintf_filtered (stream, s);
+ s = ", ";
+ (*default_scalar_print) (stream, builtin_type_int, v);
+ }
+}
+
+static void
+printf_command (arg)
+ char *arg;
+{
+ register char *f;
+ register char *s = arg;
+ char *string;
+ value *val_args;
+ int nargs = 0;
+ int allocated_args = 20;
+ char *arg_bytes;
+
+ val_args = (value *) xmalloc (allocated_args * sizeof (value));
+
+ 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 '\"'.");
+ /* doesn't return */
+
+ case '\\':
+ switch (c = *s++)
+ {
+ case '\\':
+ *f++ = '\\';
+ break;
+ case 'n':
+ *f++ = '\n';
+ break;
+ case 't':
+ *f++ = '\t';
+ break;
+ case 'r':
+ *f++ = '\r';
+ break;
+ case '"':
+ *f++ = '"';
+ break;
+ default:
+ /* ??? TODO: handle other escape sequences */
+ error ("Unrecognized \\ escape character in format string.");
+ }
+ 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++;
+
+ {
+ /* Now scan the string for %-specs and see what kinds of args they want.
+ argclass[I] classifies the %-specs so we can give vprintf something
+ of the right size. */
+
+ enum argclass {int_arg, string_arg, double_arg, long_long_arg};
+ enum argclass *argclass;
+ int nargs_wanted;
+ int argindex;
+ int lcount;
+ int i;
+
+ argclass = (enum argclass *) alloca (strlen (s) * sizeof *argclass);
+ nargs_wanted = 0;
+ f = string;
+ while (*f)
+ if (*f++ == '%')
+ {
+ lcount = 0;
+ while (index ("0123456789.hlL-+ #", *f))
+ {
+ if (*f == 'l' || *f == 'L')
+ lcount++;
+ f++;
+ }
+ if (*f == 's')
+ argclass[nargs_wanted++] = string_arg;
+ else if (*f == 'e' || *f == 'f' || *f == 'g')
+ argclass[nargs_wanted++] = double_arg;
+ else if (lcount > 1)
+ argclass[nargs_wanted++] = long_long_arg;
+ else if (*f != '%')
+ argclass[nargs_wanted++] = int_arg;
+ f++;
+ }
+
+ /* 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 *) xrealloc (val_args,
+ (allocated_args *= 2)
+ * sizeof (value));
+ 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 lay out an argument-list containing the arguments
+ as doubles, integers and C pointers. */
+
+ arg_bytes = (char *) alloca (sizeof (double) * nargs);
+ argindex = 0;
+ for (i = 0; i < nargs; i++)
+ {
+ if (argclass[i] == string_arg)
+ {
+ char *str;
+ int tem, j;
+ tem = value_as_long (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;
+
+ /* Pass address of internal copy as the arg to vprintf. */
+ *((int *) &arg_bytes[argindex]) = (int) str;
+ argindex += sizeof (int);
+ }
+ else if (VALUE_TYPE (val_args[i])->code == TYPE_CODE_FLT)
+ {
+ *((double *) &arg_bytes[argindex]) = value_as_double (val_args[i]);
+ argindex += sizeof (double);
+ }
+ else
+#ifdef LONG_LONG
+ if (argclass[i] == long_long_arg)
+ {
+ *(long long *) &arg_bytes[argindex] = value_as_long (val_args[i]);
+ argindex += sizeof (long long);
+ }
+ else
+#endif
+ {
+ *((int *) &arg_bytes[argindex]) = value_as_long (val_args[i]);
+ argindex += sizeof (int);
+ }
+ }
+ }
+ vprintf (string, arg_bytes);
+}
+
+/* Helper function for asdump_command. Finds the bounds of a function
+ for a specified section of text. PC is an address within the
+ function which you want bounds for; *LOW and *HIGH are set to the
+ beginning (inclusive) and end (exclusive) of the function. This
+ function returns 1 on success and 0 on failure. */
+
+static int
+containing_function_bounds (pc, low, high)
+ CORE_ADDR pc, *low, *high;
+{
+ int scan;
+
+ if (!find_pc_partial_function (pc, 0, low))
+ return 0;
+
+ scan = *low;
+ do {
+ scan++;
+ if (!find_pc_partial_function (scan, 0, high))
+ return 0;
+ } while (*low == *high);
+
+ return 1;
+}
+
+/* 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. */
+
+static void
+disassemble_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ CORE_ADDR low, high;
+ CORE_ADDR pc;
+ char *space_index;
+
+ if (!arg)
+ {
+ if (!selected_frame)
+ error ("No frame selected.\n");
+
+ pc = get_frame_pc (selected_frame);
+ if (!containing_function_bounds (pc, &low, &high))
+ error ("No function contains pc specified by selected frame.\n");
+ }
+ else if (!(space_index = (char *) index (arg, ' ')))
+ {
+ /* One argument. */
+ pc = parse_and_eval_address (arg);
+ if (!containing_function_bounds (pc, &low, &high))
+ error ("No function contains specified pc.\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 (!space_index)
+ {
+ char *name;
+ find_pc_partial_function (pc, &name, 0);
+ printf_filtered ("for function %s:\n", name);
+ }
+ else
+ printf_filtered ("from 0x%x to 0x%x:\n", low, high);
+
+ /* Dump the specified range. */
+ for (pc = low; pc < high; )
+ {
+ QUIT;
+ print_address (pc, stdout);
+ printf_filtered (":\t");
+ pc += print_insn (pc, stdout);
+ printf_filtered ("\n");
+ }
+ printf_filtered ("End of assembler dump.\n");
+ fflush (stdout);
+}
+
+
+extern struct cmd_list_element *enablelist, *disablelist, *deletelist;
+extern struct cmd_list_element *cmdlist, *setlist;
+
+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\
+ 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\
+ g is meaningful only with f, for type double.\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.");
+
+ add_com ("ptype", class_vars, ptype_command,
+ "Print definition of type TYPE.\n\
+Argument may be a type name defined by typedef, or \"struct STRUCTNAME\"\n\
+or \"union UNIONNAME\" or \"enum ENUMNAME\".\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.");
+
+ 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,
+"Perform an assignment VAR = EXP.\n\
+You must type the \"=\". VAR may be a debugger \"convenience\" variable\n\
+(names starting with $), a register (a few standard names starting with $),\n\
+or an actual variable in the program being debugged. EXP is any 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",
+ &setlist, "set ", 1, &cmdlist);
+
+ add_cmd ("variable", class_vars, set_command,
+ "Perform an assignment VAR = EXP.\n\
+You must type the \"=\". VAR may be a debugger \"convenience\" variable\n\
+(names starting with $), a register (a few standard names starting with $),\n\
+or an actual variable in the program being debugged. EXP is any 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)."));
+ add_com_alias ("p", "print", class_vars, 1);
+}
diff --git a/gnu/usr.bin/gdb/readline/ChangeLog b/gnu/usr.bin/gdb/readline/ChangeLog
new file mode 100644
index 0000000..b72a59d
--- /dev/null
+++ b/gnu/usr.bin/gdb/readline/ChangeLog
@@ -0,0 +1,98 @@
+Thu Feb 8 01:04:00 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * Makefile (the *other* libreadline.a): Uncomment out ranlib line.
+
+Thu Feb 1 17:50:22 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * Makefile (libreadline.a): Uncomment out ranlib line.
+
+Sun Nov 26 16:29:11 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * readline.c (rl_deprep_terminal): Only restore local_mode_flags
+ if they had been set.
+
+Thu Oct 19 17:18:40 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * Move vi_doing_insert from vi_mode.c to readline.c
+
+ * readline.c: Move compare_strings before its use.
+ Remove declarations.
+
+ * readline.c: Move defining_kbd_macro above rl_dispatch.
+ (rl_dispatch): Remove "extern int defining_kbd_macro".
+
+Mon Oct 16 11:56:03 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * readline.c (rl_set_signals): Remove unnecessary "static int
+ rl_signal_handler()".
+
+Sat Sep 30 14:51:56 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * readline.c (rl_initialize): Change parsing_conditionalized_out
+ to static.
+ (rl_dispatch): Change defining_kbd_macro to static.
+ (rl_newline): Change vi_doing_insert to static.
+
+Fri Sep 8 09:00:45 1989 Brian Fox (bfox at aurel)
+
+ * readline.c: rl_prep_terminal (). Only turn on 8th bit
+ as meta-bit iff the terminal is not using parity.
+
+Sun Sep 3 08:57:40 1989 Brian Fox (bfox at aurel)
+
+ * readline.c: start_insert (). Uses multiple
+ insertion call in cases where that makes sense.
+
+ rl_insert (). Read type-ahead buffer for additional
+ keys that are bound to rl_insert, and insert them
+ all at once. Make insertion of single keys given
+ with an argument much more efficient.
+
+Tue Aug 8 18:13:57 1989 Brian Fox (bfox at aurel)
+
+ * readline.c: Changed handling of EOF. readline () returns
+ (char *)EOF or consed string. The EOF character is read from the
+ tty, or if the tty doesn't have one, defaults to C-d.
+
+ * readline.c: Added support for event driven programs.
+ rl_event_hook is the address of a function you want called
+ while Readline is waiting for input.
+
+ * readline.c: Cleanup time. Functions without type declarations
+ do not use return with a value.
+
+ * history.c: history_expand () has new variable which is the
+ characters to ignore immediately following history_expansion_char.
+
+Sun Jul 16 08:14:00 1989 Brian Fox (bfox at aurel)
+
+ * rl_prep_terminal ()
+ BSD version turns off C-s, C-q, C-y, C-v.
+
+ * readline.c -- rl_prep_terminal ()
+ SYSV version hacks readline_echoing_p.
+ BSD version turns on passing of the 8th bit for the duration
+ of reading the line.
+
+Tue Jul 11 06:25:01 1989 Brian Fox (bfox at aurel)
+
+ * readline.c: new variable rl_tilde_expander.
+ 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.
+
+ * readline.h - new file chardefs.h
+ Separates things that only readline.c needs from the standard
+ header file publishing interesting things about readline.
+
+ * readline.c:
+ readline_default_bindings () now looks at terminal chararacters
+ and binds those as well.
+
+Wed Jun 28 20:20:51 1989 Brian Fox (bfox at aurel)
+
+ * Made readline and history into independent libraries.
+
+
diff --git a/gnu/usr.bin/gdb/readline/Makefile.gnu b/gnu/usr.bin/gdb/readline/Makefile.gnu
new file mode 100644
index 0000000..dc11539
--- /dev/null
+++ b/gnu/usr.bin/gdb/readline/Makefile.gnu
@@ -0,0 +1,114 @@
+## -*- text -*- ####################################################
+# #
+# Makefile for readline and history libraries. #
+# #
+####################################################################
+
+# Here is a rule for making .o files from .c files that doesn't force
+# the type of the machine (like -sun3) into the flags.
+.c.o:
+ $(CC) -c $(CFLAGS) $(LOCAL_INCLUDES) $(CPPFLAGS) $*.c
+
+# Destination installation directory. The libraries are copied to DESTDIR
+# when you do a `make install', and the header files to INCDIR/readline/*.h.
+DESTDIR = /usr/gnu/lib
+INCDIR = /usr/gnu/include
+
+# Define TYPES as -DVOID_SIGHANDLER if your operating system uses
+# a return type of "void" for signal handlers.
+TYPES = -DVOID_SIGHANDLER
+
+# Define SYSV as -DSYSV if you are using a System V operating system.
+#SYSV = -DSYSV
+
+# HP-UX compilation requires the BSD library.
+#LOCAL_LIBS = -lBSD
+
+# Xenix compilation requires -ldir -lx
+#LOCAL_LIBS = -ldir -lx
+
+# Comment this out if you don't think that anyone will ever desire
+# the vi line editing mode and features.
+READLINE_DEFINES = -DVI_MODE
+
+DEBUG_FLAGS = -g
+LDFLAGS = $(DEBUG_FLAGS)
+CFLAGS = $(DEBUG_FLAGS) $(TYPE) $(SYSV) -I.
+
+# A good alternative is gcc -traditional.
+#CC = gcc -traditional
+CC = cc
+RANLIB = /usr/bin/ranlib
+AR = ar
+RM = rm
+CP = cp
+
+LOCAL_INCLUDES = -I../
+
+CSOURCES = readline.c history.c funmap.c keymaps.c vi_mode.c \
+ emacs_keymap.c vi_keymap.c keymaps.c
+
+HSOURCES = readline.h chardefs.h history.h keymaps.h
+SOURCES = $(CSOURCES) $(HSOURCES)
+
+DOCUMENTATION = readline.texinfo inc-readline.texinfo \
+ history.texinfo inc-history.texinfo
+
+SUPPORT = COPYING Makefile $(DOCUMENTATION) ChangeLog
+
+THINGS_TO_TAR = $(SOURCES) $(SUPPORT)
+
+##########################################################################
+
+all: libreadline.a
+
+libreadline.a: readline.o history.o funmap.o keymaps.o
+ $(RM) -f libreadline.a
+ $(AR) clq libreadline.a readline.o history.o funmap.o keymaps.o
+ if [ -f $(RANLIB) ]; then $(RANLIB) libreadline.a; fi
+
+readline.o: readline.h chardefs.h keymaps.h history.h readline.c vi_mode.c
+ $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \
+ $(LOCAL_INCLUDES) $*.c
+
+history.o: history.c history.h
+ $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \
+ $(LOCAL_INCLUDES) $*.c
+
+funmap.o: readline.h
+ $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \
+ $(LOCAL_INCLUDES) $*.c
+
+keymaps.o: emacs_keymap.c vi_keymap.c keymaps.h chardefs.h keymaps.c
+ $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \
+ $(LOCAL_INCLUDES) $*.c
+
+libtest: libreadline.a libtest.c
+ $(CC) -o libtest $(CFLAGS) $(CPPFLAGS) -L. libtest.c -lreadline -ltermcap
+
+readline: readline.c history.o keymaps.o funmap.o readline.h chardefs.h
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \
+ $(LOCAL_INCLUDES) -DTEST -o readline readline.c funmap.o \
+ keymaps.o history.o -L. -ltermcap
+
+readline.tar: $(THINGS_TO_TAR)
+ tar -cf readline.tar $(THINGS_TO_TAR)
+
+readline.tar.Z: readline.tar
+ compress -f readline.tar
+
+install: $(DESTDIR)/libreadline.a includes
+
+includes:
+ if [ ! -r $(INCDIR)/readline ]; then\
+ mkdir $(INCDIR)/readline;\
+ chmod a+r $(INCDIR)/readline;\
+ fi
+ $(CP) readline.h keymaps.h chardefs.h $(INCDIR)/readline/
+clean:
+ rm -f *.o *.a *.log *.cp *.tp *.vr *.fn *.aux *.pg *.toc
+
+$(DESTDIR)/libreadline.a: libreadline.a
+ -mv $(DESTDIR)/libreadline.a $(DESTDIR)/libreadline.old
+ cp libreadline.a $(DESTDIR)/libreadline.a
+ $(RANLIB) -t $(DESTDIR)/libreadline.a
diff --git a/gnu/usr.bin/gdb/readline/chardefs.h b/gnu/usr.bin/gdb/readline/chardefs.h
new file mode 100644
index 0000000..9749ae4
--- /dev/null
+++ b/gnu/usr.bin/gdb/readline/chardefs.h
@@ -0,0 +1,50 @@
+/* chardefs.h -- Character definitions for readline. */
+#ifndef _CHARDEFS_
+
+#ifndef savestring
+#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
+#endif
+
+#ifndef whitespace
+#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
+#endif
+
+#ifdef CTRL
+#undef CTRL
+#endif
+
+/* Some character stuff. */
+#define control_character_threshold 0x020 /* smaller than this is control */
+#define meta_character_threshold 0x07f /* larger than this is Meta. */
+#define control_character_bit 0x40 /* 0x000000, must be off. */
+#define meta_character_bit 0x080 /* x0000000, must be on. */
+
+#define CTRL(c) ((c) & (~control_character_bit))
+#define META(c) ((c) | meta_character_bit)
+
+#define UNMETA(c) ((c) & (~meta_character_bit))
+#define UNCTRL(c) to_upper(((c)|control_character_bit))
+
+#define lowercase_p(c) (((c) > ('a' - 1) && (c) < ('z' + 1)))
+#define uppercase_p(c) (((c) > ('A' - 1) && (c) < ('Z' + 1)))
+
+#define pure_alphabetic(c) (lowercase_p(c) || uppercase_p(c))
+
+#ifndef to_upper
+#define to_upper(c) (lowercase_p(c) ? ((c) - 32) : (c))
+#define to_lower(c) (uppercase_p(c) ? ((c) + 32) : (c))
+#endif
+
+#define CTRL_P(c) ((c) < control_character_threshold)
+#define META_P(c) ((c) > meta_character_threshold)
+
+#define NEWLINE '\n'
+#define RETURN CTRL('M')
+#define RUBOUT 0x07f
+#define TAB '\t'
+#define ABORT_CHAR CTRL('G')
+#define PAGE CTRL('L')
+#define SPACE 0x020
+#define ESC CTRL('[')
+
+#endif /* _CHARDEFS_ */
diff --git a/gnu/usr.bin/gdb/readline/emacs_keymap.c b/gnu/usr.bin/gdb/readline/emacs_keymap.c
new file mode 100644
index 0000000..7030e69
--- /dev/null
+++ b/gnu/usr.bin/gdb/readline/emacs_keymap.c
@@ -0,0 +1,472 @@
+/* emacs_keymap.c -- the keymap for emacs_mode in readline (). */
+
+/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
+
+ This file is part of GNU Readline, a library for reading lines
+ of text with interactive input and history editing.
+
+ Readline is free software; you can 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.
+
+ Readline is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Readline; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef FILE
+#include <stdio.h>
+#endif /* FILE */
+
+#include "readline.h"
+
+/* An array of function pointers, one for each possible key.
+ If the type byte is ISKMAP, then the pointer is the address of
+ a keymap. */
+
+KEYMAP_ENTRY_ARRAY emacs_standard_keymap = {
+
+ /* Control keys. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, rl_beg_of_line }, /* Control-a */
+ { ISFUNC, rl_backward }, /* Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Control-c */
+ { ISFUNC, rl_delete }, /* Control-d */
+ { ISFUNC, rl_end_of_line }, /* Control-e */
+ { ISFUNC, rl_forward }, /* Control-f */
+ { ISFUNC, rl_abort }, /* Control-g */
+ { ISFUNC, rl_backward }, /* Control-h */
+ { ISFUNC, rl_complete }, /* Control-i */
+ { ISFUNC, rl_newline }, /* Control-j */
+ { ISFUNC, rl_kill_line }, /* Control-k */
+ { ISFUNC, rl_clear_screen }, /* Control-l */
+ { ISFUNC, rl_newline }, /* Control-m */
+ { ISFUNC, rl_get_next_history }, /* Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Control-o */
+ { ISFUNC, rl_get_previous_history }, /* Control-p */
+ { ISFUNC, rl_quoted_insert }, /* Control-q */
+ { ISFUNC, rl_reverse_search_history }, /* Control-r */
+ { ISFUNC, rl_forward_search_history }, /* Control-s */
+ { ISFUNC, rl_transpose_chars }, /* Control-t */
+ { ISFUNC, rl_unix_line_discard }, /* Control-u */
+ { ISFUNC, rl_quoted_insert }, /* Control-v */
+ { ISFUNC, rl_unix_word_rubout }, /* Control-w */
+ { ISKMAP, (Function *)emacs_ctlx_keymap }, /* Control-x */
+ { ISFUNC, rl_yank }, /* Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Control-z */
+ { ISKMAP, (Function *)emacs_meta_keymap }, /* Control-[ */
+ { ISFUNC, (Function *)0x0 }, /* Control-\ */
+ { ISFUNC, (Function *)0x0 }, /* Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Control-^ */
+ { ISFUNC, rl_undo_command }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, rl_insert }, /* SPACE */
+ { ISFUNC, rl_insert }, /* ! */
+ { ISFUNC, rl_insert }, /* " */
+ { ISFUNC, rl_insert }, /* # */
+ { ISFUNC, rl_insert }, /* $ */
+ { ISFUNC, rl_insert }, /* % */
+ { ISFUNC, rl_insert }, /* & */
+ { ISFUNC, rl_insert }, /* ' */
+ { ISFUNC, rl_insert }, /* ( */
+ { ISFUNC, rl_insert }, /* ) */
+ { ISFUNC, rl_insert }, /* * */
+ { ISFUNC, rl_insert }, /* + */
+ { ISFUNC, rl_insert }, /* , */
+ { ISFUNC, rl_insert }, /* - */
+ { ISFUNC, rl_insert }, /* . */
+ { ISFUNC, rl_insert }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, rl_insert }, /* 0 */
+ { ISFUNC, rl_insert }, /* 1 */
+ { ISFUNC, rl_insert }, /* 2 */
+ { ISFUNC, rl_insert }, /* 3 */
+ { ISFUNC, rl_insert }, /* 4 */
+ { ISFUNC, rl_insert }, /* 5 */
+ { ISFUNC, rl_insert }, /* 6 */
+ { ISFUNC, rl_insert }, /* 7 */
+ { ISFUNC, rl_insert }, /* 8 */
+ { ISFUNC, rl_insert }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, rl_insert }, /* : */
+ { ISFUNC, rl_insert }, /* ; */
+ { ISFUNC, rl_insert }, /* < */
+ { ISFUNC, rl_insert }, /* = */
+ { ISFUNC, rl_insert }, /* > */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_insert }, /* A */
+ { ISFUNC, rl_insert }, /* B */
+ { ISFUNC, rl_insert }, /* C */
+ { ISFUNC, rl_insert }, /* D */
+ { ISFUNC, rl_insert }, /* E */
+ { ISFUNC, rl_insert }, /* F */
+ { ISFUNC, rl_insert }, /* G */
+ { ISFUNC, rl_insert }, /* H */
+ { ISFUNC, rl_insert }, /* I */
+ { ISFUNC, rl_insert }, /* J */
+ { ISFUNC, rl_insert }, /* K */
+ { ISFUNC, rl_insert }, /* L */
+ { ISFUNC, rl_insert }, /* M */
+ { ISFUNC, rl_insert }, /* N */
+ { ISFUNC, rl_insert }, /* O */
+ { ISFUNC, rl_insert }, /* P */
+ { ISFUNC, rl_insert }, /* Q */
+ { ISFUNC, rl_insert }, /* R */
+ { ISFUNC, rl_insert }, /* S */
+ { ISFUNC, rl_insert }, /* T */
+ { ISFUNC, rl_insert }, /* U */
+ { ISFUNC, rl_insert }, /* V */
+ { ISFUNC, rl_insert }, /* W */
+ { ISFUNC, rl_insert }, /* X */
+ { ISFUNC, rl_insert }, /* Y */
+ { ISFUNC, rl_insert }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, rl_insert }, /* [ */
+ { ISFUNC, rl_insert }, /* \ */
+ { ISFUNC, rl_insert }, /* ] */
+ { ISFUNC, rl_insert }, /* ^ */
+ { ISFUNC, rl_insert }, /* _ */
+ { ISFUNC, rl_insert }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, rl_insert }, /* a */
+ { ISFUNC, rl_insert }, /* b */
+ { ISFUNC, rl_insert }, /* c */
+ { ISFUNC, rl_insert }, /* d */
+ { ISFUNC, rl_insert }, /* e */
+ { ISFUNC, rl_insert }, /* f */
+ { ISFUNC, rl_insert }, /* g */
+ { ISFUNC, rl_insert }, /* h */
+ { ISFUNC, rl_insert }, /* i */
+ { ISFUNC, rl_insert }, /* j */
+ { ISFUNC, rl_insert }, /* k */
+ { ISFUNC, rl_insert }, /* l */
+ { ISFUNC, rl_insert }, /* m */
+ { ISFUNC, rl_insert }, /* n */
+ { ISFUNC, rl_insert }, /* o */
+ { ISFUNC, rl_insert }, /* p */
+ { ISFUNC, rl_insert }, /* q */
+ { ISFUNC, rl_insert }, /* r */
+ { ISFUNC, rl_insert }, /* s */
+ { ISFUNC, rl_insert }, /* t */
+ { ISFUNC, rl_insert }, /* u */
+ { ISFUNC, rl_insert }, /* v */
+ { ISFUNC, rl_insert }, /* w */
+ { ISFUNC, rl_insert }, /* x */
+ { ISFUNC, rl_insert }, /* y */
+ { ISFUNC, rl_insert }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, rl_insert }, /* { */
+ { ISFUNC, rl_insert }, /* | */
+ { ISFUNC, rl_insert }, /* } */
+ { ISFUNC, rl_insert }, /* ~ */
+ { ISFUNC, rl_rubout } /* RUBOUT */
+};
+
+KEYMAP_ENTRY_ARRAY emacs_meta_keymap = {
+
+ /* Meta keys. Just like above, but the high bit is set. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-@ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-a */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-c */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-d */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-e */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-f */
+ { ISFUNC, rl_abort }, /* Meta-Control-g */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-h */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-i */
+ { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-j */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-k */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-l */
+ { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-m */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-o */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-p */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-q */
+ { ISFUNC, rl_revert_line }, /* Meta-Control-r */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-s */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-t */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-u */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-v */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-w */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-x */
+ { ISFUNC, rl_yank_nth_arg }, /* Meta-Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-z */
+
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-[ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-\ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-^ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-SPACE */
+ { ISFUNC, (Function *)0x0 }, /* Meta-! */
+ { ISFUNC, (Function *)0x0 }, /* Meta-" */
+ { ISFUNC, (Function *)0x0 }, /* Meta-# */
+ { ISFUNC, (Function *)0x0 }, /* Meta-$ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-% */
+ { ISFUNC, (Function *)0x0 }, /* Meta-& */
+ { ISFUNC, (Function *)0x0 }, /* Meta-' */
+ { ISFUNC, (Function *)0x0 }, /* Meta-( */
+ { ISFUNC, (Function *)0x0 }, /* Meta-) */
+ { ISFUNC, (Function *)0x0 }, /* Meta-* */
+ { ISFUNC, (Function *)0x0 }, /* Meta-+ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-, */
+ { ISFUNC, rl_digit_argument }, /* Meta-- */
+ { ISFUNC, (Function *)0x0 }, /* Meta-. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-/ */
+
+ /* Regular digits. */
+ { ISFUNC, rl_digit_argument }, /* Meta-0 */
+ { ISFUNC, rl_digit_argument }, /* Meta-1 */
+ { ISFUNC, rl_digit_argument }, /* Meta-2 */
+ { ISFUNC, rl_digit_argument }, /* Meta-3 */
+ { ISFUNC, rl_digit_argument }, /* Meta-4 */
+ { ISFUNC, rl_digit_argument }, /* Meta-5 */
+ { ISFUNC, rl_digit_argument }, /* Meta-6 */
+ { ISFUNC, rl_digit_argument }, /* Meta-7 */
+ { ISFUNC, rl_digit_argument }, /* Meta-8 */
+ { ISFUNC, rl_digit_argument }, /* Meta-9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-: */
+ { ISFUNC, (Function *)0x0 }, /* Meta-; */
+ { ISFUNC, rl_beginning_of_history }, /* Meta-< */
+ { ISFUNC, (Function *)0x0 }, /* Meta-= */
+ { ISFUNC, rl_end_of_history }, /* Meta-> */
+ { ISFUNC, rl_possible_completions }, /* Meta-? */
+ { ISFUNC, (Function *)0x0 }, /* Meta-@ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-A */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-B */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-C */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-D */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-E */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-F */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-G */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-H */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-I */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-J */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-K */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-L */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-M */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-N */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-O */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-P */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-Q */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-R */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-S */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-T */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-U */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-V */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-W */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-X */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-Y */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-[ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-\ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-] */
+ { ISFUNC, (Function *)0x0 }, /* Meta-^ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-_ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-a */
+ { ISFUNC, rl_backward_word }, /* Meta-b */
+ { ISFUNC, rl_capitalize_word }, /* Meta-c */
+ { ISFUNC, rl_kill_word }, /* Meta-d */
+ { ISFUNC, (Function *)0x0 }, /* Meta-e */
+ { ISFUNC, rl_forward_word }, /* Meta-f */
+ { ISFUNC, (Function *)0x0 }, /* Meta-g */
+ { ISFUNC, (Function *)0x0 }, /* Meta-h */
+ { ISFUNC, (Function *)0x0 }, /* Meta-i */
+ { ISFUNC, (Function *)0x0 }, /* Meta-j */
+ { ISFUNC, (Function *)0x0 }, /* Meta-k */
+ { ISFUNC, rl_downcase_word }, /* Meta-l */
+ { ISFUNC, (Function *)0x0 }, /* Meta-m */
+ { ISFUNC, (Function *)0x0 }, /* Meta-n */
+ { ISFUNC, (Function *)0x0 }, /* Meta-o */
+ { ISFUNC, (Function *)0x0 }, /* Meta-p */
+ { ISFUNC, (Function *)0x0 }, /* Meta-q */
+ { ISFUNC, rl_revert_line }, /* Meta-r */
+ { ISFUNC, (Function *)0x0 }, /* Meta-s */
+ { ISFUNC, rl_transpose_words }, /* Meta-t */
+ { ISFUNC, rl_upcase_word }, /* Meta-u */
+ { ISFUNC, (Function *)0x0 }, /* Meta-v */
+ { ISFUNC, (Function *)0x0 }, /* Meta-w */
+ { ISFUNC, (Function *)0x0 }, /* Meta-x */
+ { ISFUNC, rl_yank_pop }, /* Meta-y */
+ { ISFUNC, (Function *)0x0 }, /* Meta-z */
+
+ /* Final punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-{ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-| */
+ { ISFUNC, (Function *)0x0 }, /* Meta-} */
+ { ISFUNC, (Function *)0x0 }, /* Meta-~ */
+ { ISFUNC, rl_backward_kill_word } /* Meta-rubout */
+};
+
+KEYMAP_ENTRY_ARRAY emacs_ctlx_keymap = {
+
+ /* Control keys. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, (Function *)0x0 }, /* Control-a */
+ { ISFUNC, (Function *)0x0 }, /* Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Control-c */
+ { ISFUNC, (Function *)0x0 }, /* Control-d */
+ { ISFUNC, (Function *)0x0 }, /* Control-e */
+ { ISFUNC, (Function *)0x0 }, /* Control-f */
+ { ISFUNC, rl_abort }, /* Control-g */
+ { ISFUNC, (Function *)0x0 }, /* Control-h */
+ { ISFUNC, (Function *)0x0 }, /* Control-i */
+ { ISFUNC, (Function *)0x0 }, /* Control-j */
+ { ISFUNC, (Function *)0x0 }, /* Control-k */
+ { ISFUNC, (Function *)0x0 }, /* Control-l */
+ { ISFUNC, (Function *)0x0 }, /* Control-m */
+ { ISFUNC, (Function *)0x0 }, /* Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Control-o */
+ { ISFUNC, (Function *)0x0 }, /* Control-p */
+ { ISFUNC, (Function *)0x0 }, /* Control-q */
+ { ISFUNC, rl_re_read_init_file }, /* Control-r */
+ { ISFUNC, (Function *)0x0 }, /* Control-s */
+ { ISFUNC, (Function *)0x0 }, /* Control-t */
+ { ISFUNC, rl_undo_command }, /* Control-u */
+ { ISFUNC, (Function *)0x0 }, /* Control-v */
+ { ISFUNC, (Function *)0x0 }, /* Control-w */
+ { ISFUNC, (Function *)0x0 }, /* Control-x */
+ { ISFUNC, (Function *)0x0 }, /* Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Control-z */
+ { ISFUNC, (Function *)0x0 }, /* Control-[ */
+ { ISFUNC, (Function *)0x0 }, /* Control-\ */
+ { ISFUNC, (Function *)0x0 }, /* Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Control-^ */
+ { ISFUNC, (Function *)0x0 }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, (Function *)0x0 }, /* SPACE */
+ { ISFUNC, (Function *)0x0 }, /* ! */
+ { ISFUNC, (Function *)0x0 }, /* " */
+ { ISFUNC, (Function *)0x0 }, /* # */
+ { ISFUNC, (Function *)0x0 }, /* $ */
+ { ISFUNC, (Function *)0x0 }, /* % */
+ { ISFUNC, (Function *)0x0 }, /* & */
+ { ISFUNC, (Function *)0x0 }, /* ' */
+ { ISFUNC, rl_start_kbd_macro }, /* ( */
+ { ISFUNC, rl_end_kbd_macro }, /* ) */
+ { ISFUNC, (Function *)0x0 }, /* * */
+ { ISFUNC, (Function *)0x0 }, /* + */
+ { ISFUNC, (Function *)0x0 }, /* , */
+ { ISFUNC, (Function *)0x0 }, /* - */
+ { ISFUNC, (Function *)0x0 }, /* . */
+ { ISFUNC, (Function *)0x0 }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, (Function *)0x0 }, /* 0 */
+ { ISFUNC, (Function *)0x0 }, /* 1 */
+ { ISFUNC, (Function *)0x0 }, /* 2 */
+ { ISFUNC, (Function *)0x0 }, /* 3 */
+ { ISFUNC, (Function *)0x0 }, /* 4 */
+ { ISFUNC, (Function *)0x0 }, /* 5 */
+ { ISFUNC, (Function *)0x0 }, /* 6 */
+ { ISFUNC, (Function *)0x0 }, /* 7 */
+ { ISFUNC, (Function *)0x0 }, /* 8 */
+ { ISFUNC, (Function *)0x0 }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* : */
+ { ISFUNC, (Function *)0x0 }, /* ; */
+ { ISFUNC, (Function *)0x0 }, /* < */
+ { ISFUNC, (Function *)0x0 }, /* = */
+ { ISFUNC, (Function *)0x0 }, /* > */
+ { ISFUNC, (Function *)0x0 }, /* ? */
+ { ISFUNC, (Function *)0x0 }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_do_lowercase_version }, /* A */
+ { ISFUNC, rl_do_lowercase_version }, /* B */
+ { ISFUNC, rl_do_lowercase_version }, /* C */
+ { ISFUNC, rl_do_lowercase_version }, /* D */
+ { ISFUNC, rl_do_lowercase_version }, /* E */
+ { ISFUNC, rl_do_lowercase_version }, /* F */
+ { ISFUNC, rl_do_lowercase_version }, /* G */
+ { ISFUNC, rl_do_lowercase_version }, /* H */
+ { ISFUNC, rl_do_lowercase_version }, /* I */
+ { ISFUNC, rl_do_lowercase_version }, /* J */
+ { ISFUNC, rl_do_lowercase_version }, /* K */
+ { ISFUNC, rl_do_lowercase_version }, /* L */
+ { ISFUNC, rl_do_lowercase_version }, /* M */
+ { ISFUNC, rl_do_lowercase_version }, /* N */
+ { ISFUNC, rl_do_lowercase_version }, /* O */
+ { ISFUNC, rl_do_lowercase_version }, /* P */
+ { ISFUNC, rl_do_lowercase_version }, /* Q */
+ { ISFUNC, rl_do_lowercase_version }, /* R */
+ { ISFUNC, rl_do_lowercase_version }, /* S */
+ { ISFUNC, rl_do_lowercase_version }, /* T */
+ { ISFUNC, rl_do_lowercase_version }, /* U */
+ { ISFUNC, rl_do_lowercase_version }, /* V */
+ { ISFUNC, rl_do_lowercase_version }, /* W */
+ { ISFUNC, rl_do_lowercase_version }, /* X */
+ { ISFUNC, rl_do_lowercase_version }, /* Y */
+ { ISFUNC, rl_do_lowercase_version }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* [ */
+ { ISFUNC, (Function *)0x0 }, /* \ */
+ { ISFUNC, (Function *)0x0 }, /* ] */
+ { ISFUNC, (Function *)0x0 }, /* ^ */
+ { ISFUNC, (Function *)0x0 }, /* _ */
+ { ISFUNC, (Function *)0x0 }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, (Function *)0x0 }, /* a */
+ { ISFUNC, (Function *)0x0 }, /* b */
+ { ISFUNC, (Function *)0x0 }, /* c */
+ { ISFUNC, (Function *)0x0 }, /* d */
+ { ISFUNC, rl_call_last_kbd_macro }, /* e */
+ { ISFUNC, (Function *)0x0 }, /* f */
+ { ISFUNC, (Function *)0x0 }, /* g */
+ { ISFUNC, (Function *)0x0 }, /* h */
+ { ISFUNC, (Function *)0x0 }, /* i */
+ { ISFUNC, (Function *)0x0 }, /* j */
+ { ISFUNC, (Function *)0x0 }, /* k */
+ { ISFUNC, (Function *)0x0 }, /* l */
+ { ISFUNC, (Function *)0x0 }, /* m */
+ { ISFUNC, (Function *)0x0 }, /* n */
+ { ISFUNC, (Function *)0x0 }, /* o */
+ { ISFUNC, (Function *)0x0 }, /* p */
+ { ISFUNC, (Function *)0x0 }, /* q */
+ { ISFUNC, rl_re_read_init_file }, /* r */
+ { ISFUNC, (Function *)0x0 }, /* s */
+ { ISFUNC, (Function *)0x0 }, /* t */
+ { ISFUNC, (Function *)0x0 }, /* u */
+ { ISFUNC, (Function *)0x0 }, /* v */
+ { ISFUNC, (Function *)0x0 }, /* w */
+ { ISFUNC, (Function *)0x0 }, /* x */
+ { ISFUNC, (Function *)0x0 }, /* y */
+ { ISFUNC, (Function *)0x0 }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* { */
+ { ISFUNC, (Function *)0x0 }, /* | */
+ { ISFUNC, (Function *)0x0 }, /* } */
+ { ISFUNC, (Function *)0x0 }, /* ~ */
+ { ISFUNC, rl_backward_kill_line } /* RUBOUT */
+};
diff --git a/gnu/usr.bin/gdb/readline/funmap.c b/gnu/usr.bin/gdb/readline/funmap.c
new file mode 100644
index 0000000..357e716
--- /dev/null
+++ b/gnu/usr.bin/gdb/readline/funmap.c
@@ -0,0 +1,217 @@
+/* funmap.c -- attach names to functions. */
+
+/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
+
+ This file is part of GNU Readline, a library for reading lines
+ of text with interactive input and history editing.
+
+ Readline is free software; you can 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.
+
+ Readline is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Readline; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define STATIC_MALLOC
+#ifndef STATIC_MALLOC
+extern char *xmalloc (), *xrealloc ();
+#else
+static char *xmalloc (), *xrealloc ();
+#endif
+
+#ifndef FILE
+#include <stdio.h>
+#endif /* FILE */
+
+#include "readline.h"
+
+FUNMAP **funmap = (FUNMAP **)NULL;
+static int funmap_size = 0;
+
+static int just_testing_ar_tmp = 0;
+static int just_testing_ar_tmp_2 = 5;
+int foo_testing_ar;
+
+static int funmap_entry = 0;
+
+static FUNMAP default_funmap[] = {
+ { "beginning-of-line", rl_beg_of_line },
+ { "backward-char", rl_backward },
+ { "delete-char", rl_delete },
+ { "end-of-line", rl_end_of_line },
+ { "forward-char", rl_forward },
+ { "accept-line", rl_newline },
+ { "kill-line", rl_kill_line },
+ { "clear-screen", rl_clear_screen },
+ { "next-history", rl_get_next_history },
+ { "previous-history", rl_get_previous_history },
+ { "quoted-insert", rl_quoted_insert },
+ { "reverse-search-history", rl_reverse_search_history },
+ { "forward-search-history", rl_forward_search_history },
+ { "transpose-chars", rl_transpose_chars },
+ { "unix-line-discard", rl_unix_line_discard },
+ { "unix-word-rubout", rl_unix_word_rubout },
+ { "yank", rl_yank },
+ { "yank-pop", rl_yank_pop },
+ { "yank-nth-arg", rl_yank_nth_arg },
+ { "backward-delete-char", rl_rubout },
+ { "backward-word", rl_backward_word },
+ { "kill-word", rl_kill_word },
+ { "forward-word", rl_forward_word },
+ { "tab-insert", rl_tab_insert },
+ { "backward-kill-word", rl_backward_kill_word },
+ { "backward-kill-line", rl_backward_kill_line },
+ { "transpose-words", rl_transpose_words },
+ { "digit-argument", rl_digit_argument },
+ { "complete", rl_complete },
+ { "possible-completions", rl_possible_completions },
+ { "do-lowercase-version", rl_do_lowercase_version },
+ { "digit-argument", rl_digit_argument },
+ { "universal-argument", rl_universal_argument },
+ { "abort", rl_abort },
+ { "undo", rl_undo_command },
+ { "upcase-word", rl_upcase_word },
+ { "downcase-word", rl_downcase_word },
+ { "capitalize-word", rl_capitalize_word },
+ { "revert-line", rl_revert_line },
+ { "beginning-of-history", rl_beginning_of_history },
+ { "end-of-history", rl_end_of_history },
+ { "self-insert", rl_insert },
+ { "start-kbd-macro", rl_start_kbd_macro },
+ { "end-kbd-macro", rl_end_kbd_macro },
+ { "re-read-init-file", rl_re_read_init_file },
+#ifdef VI_MODE
+ { "vi-movement-mode", rl_vi_movement_mode },
+ { "vi-insertion-mode", rl_vi_insertion_mode },
+ { "vi-arg-digit", rl_vi_arg_digit },
+ { "vi-prev-word", rl_vi_prev_word },
+ { "vi-next-word", rl_vi_next_word },
+ { "vi-char-search", rl_vi_char_search },
+ { "vi-editing-mode", rl_vi_editing_mode },
+ { "vi-eof-maybe", rl_vi_eof_maybe },
+ { "vi-append-mode", rl_vi_append_mode },
+ { "vi-put", rl_vi_put },
+ { "vi-append-eol", rl_vi_append_eol },
+ { "vi-insert-beg", rl_vi_insert_beg },
+ { "vi-delete", rl_vi_delete },
+ { "vi-comment", rl_vi_comment },
+ { "vi-first-print", rl_vi_first_print },
+ { "vi-fword", rl_vi_fword },
+ { "vi-fWord", rl_vi_fWord },
+ { "vi-bword", rl_vi_bword },
+ { "vi-bWord", rl_vi_bWord },
+ { "vi-eword", rl_vi_eword },
+ { "vi-eWord", rl_vi_eWord },
+ { "vi-end-word", rl_vi_end_word },
+ { "vi-change-case", rl_vi_change_case },
+ { "vi-match", rl_vi_match },
+ { "vi-bracktype", rl_vi_bracktype },
+ { "vi-change-char", rl_vi_change_char },
+ { "vi-yank-arg", rl_vi_yank_arg },
+ { "vi-search", rl_vi_search },
+ { "vi-search-again", rl_vi_search_again },
+ { "vi-dosearch", rl_vi_dosearch },
+ { "vi-subst", rl_vi_subst },
+ { "vi-overstrike", rl_vi_overstrike },
+ { "vi-overstrike-delete", rl_vi_overstrike_delete },
+ { "vi-replace, ", rl_vi_replace },
+ { "vi-column", rl_vi_column },
+ { "vi-delete-to", rl_vi_delete_to },
+ { "vi-change-to", rl_vi_change_to },
+ { "vi-yank-to", rl_vi_yank_to },
+ { "vi-complete", rl_vi_complete },
+#endif /* VI_MODE */
+
+ {(char *)NULL, (Function *)NULL }
+};
+
+rl_add_funmap_entry (name, function)
+ char *name;
+ Function *function;
+{
+ if (funmap_entry + 2 >= funmap_size)
+ if (!funmap)
+ funmap = (FUNMAP **)xmalloc ((funmap_size = 80) * sizeof (FUNMAP *));
+ else
+ funmap =
+ (FUNMAP **)xrealloc (funmap, (funmap_size += 80) * sizeof (FUNMAP *));
+
+ funmap[funmap_entry] = (FUNMAP *)xmalloc (sizeof (FUNMAP));
+ funmap[funmap_entry]->name = name;
+ funmap[funmap_entry]->function = function;
+
+ funmap[++funmap_entry] = (FUNMAP *)NULL;
+}
+
+static int funmap_initialized = 0;
+
+/* Make the funmap contain all of the default entries. */
+rl_initialize_funmap ()
+{
+ register int i;
+
+ if (funmap_initialized)
+ return;
+
+ for (i = 0; default_funmap[i].name; i++)
+ rl_add_funmap_entry (default_funmap[i].name, default_funmap[i].function);
+
+ funmap_initialized = 1;
+}
+
+/* Things that mean `Control'. */
+char *possible_control_prefixes[] = {
+ "Control-", "C-", "CTRL-", (char *)NULL
+};
+
+char *possible_meta_prefixes[] = {
+ "Meta", "M-", (char *)NULL
+};
+
+#ifdef STATIC_MALLOC
+
+/* **************************************************************** */
+/* */
+/* xmalloc and xrealloc () */
+/* */
+/* **************************************************************** */
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ static memory_error_and_abort ();
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ static memory_error_and_abort ();
+ char *temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static
+memory_error_and_abort ()
+{
+ fprintf (stderr, "history: Out of virtual memory!\n");
+ abort ();
+}
+#endif /* STATIC_MALLOC */
diff --git a/gnu/usr.bin/gdb/readline/history.c b/gnu/usr.bin/gdb/readline/history.c
new file mode 100644
index 0000000..7087718
--- /dev/null
+++ b/gnu/usr.bin/gdb/readline/history.c
@@ -0,0 +1,1462 @@
+/* History.c -- standalone history library */
+
+/* Copyright (C) 1989 Free Software Foundation, Inc.
+
+ This file contains the GNU History Library (the Library), a set of
+ routines for managing the text of previously typed lines.
+
+ The Library is free software; you can 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.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The goal is to make the implementation transparent, so that you
+ don't have to know what data types are used, just what functions
+ you can call. I think I have done that. */
+
+/* Remove these declarations when we have a complete libgnu.a. */
+#define STATIC_MALLOC
+#ifndef STATIC_MALLOC
+extern char *xmalloc (), *xrealloc ();
+#else
+static char *xmalloc (), *xrealloc ();
+#endif
+
+#include <stdio.h>
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#if defined (sparc) && defined (sun)
+#include <alloca.h>
+#else
+extern char *alloca ();
+#endif
+#endif
+
+#include "history.h"
+
+#ifndef savestring
+#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
+#endif
+
+#ifndef whitespace
+#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
+#endif
+
+#ifndef digit
+#define digit(c) ((c) >= '0' && (c) <= '9')
+#endif
+
+#ifndef member
+#define member(c, s) ((c) ? index ((s), (c)) : 0)
+#endif
+
+/* **************************************************************** */
+/* */
+/* History functions */
+/* */
+/* **************************************************************** */
+
+/* An array of HIST_ENTRY. This is where we store the history. */
+static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
+
+/* Non-zero means that we have enforced a limit on the amount of
+ history that we save. */
+static int history_stifled = 0;
+
+/* If HISTORY_STIFLED is non-zero, then this is the maximum number of
+ entries to remember. */
+static int max_input_history;
+
+/* The current location of the interactive history pointer. Just makes
+ life easier for outside callers. */
+static int history_offset = 0;
+
+/* The number of strings currently stored in the input_history list. */
+static int history_length = 0;
+
+/* The current number of slots allocated to the input_history. */
+static int history_size = 0;
+
+/* The number of slots to increase the_history by. */
+#define DEFAULT_HISTORY_GROW_SIZE 50
+
+/* The character that represents the start of a history expansion
+ request. This is usually `!'. */
+char history_expansion_char = '!';
+
+/* The character that invokes word substitution if found at the start of
+ a line. This is usually `^'. */
+char history_subst_char = '^';
+
+/* During tokenization, if this character is seen as the first character
+ of a word, then it, and all subsequent characters upto a newline are
+ ignored. For a Bourne shell, this should be '#'. Bash special cases
+ the interactive comment character to not be a comment delimiter. */
+char history_comment_char = '\0';
+
+/* The list of characters which inhibit the expansion of text if found
+ immediately following history_expansion_char. */
+char *history_no_expand_chars = " \t\n\r=";
+
+/* The logical `base' of the history array. It defaults to 1. */
+int history_base = 1;
+
+/* Begin a session in which the history functions might be used. This
+ initializes interactive variables. */
+void
+using_history ()
+{
+ history_offset = history_length;
+}
+
+/* Place STRING at the end of the history list. The data field
+ is set to NULL. */
+void
+add_history (string)
+ char *string;
+{
+ HIST_ENTRY *temp;
+
+ if (history_stifled && (history_length == max_input_history)) {
+ register int i;
+
+ /* If the history is stifled, and history_length is zero,
+ and it equals max_input_history, we don't save items. */
+ if (!history_length)
+ return;
+
+ /* If there is something in the slot, then remove it. */
+ if (the_history[0]) {
+ free (the_history[0]->line);
+ free (the_history[0]);
+ }
+
+ for (i = 0; i < history_length; i++)
+ the_history[i] = the_history[i + 1];
+
+ history_base++;
+
+ } else {
+
+ if (!history_size) {
+ the_history =
+ (HIST_ENTRY **)xmalloc ((history_size = DEFAULT_HISTORY_GROW_SIZE)
+ * sizeof (HIST_ENTRY *));
+ history_length = 1;
+
+ } else {
+ if (history_length == (history_size - 1)) {
+ the_history =
+ (HIST_ENTRY **)xrealloc (the_history,
+ ((history_size += DEFAULT_HISTORY_GROW_SIZE)
+ * sizeof (HIST_ENTRY *)));
+ }
+ history_length++;
+ }
+ }
+
+ temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+ temp->line = savestring (string);
+ temp->data = (char *)NULL;
+
+ the_history[history_length] = (HIST_ENTRY *)NULL;
+ the_history[history_length - 1] = temp;
+}
+
+/* Make the history entry at WHICH have LINE and DATA. This returns
+ the old entry so you can dispose of the data. In the case of an
+ invalid WHICH, a NULL pointer is returned. */
+HIST_ENTRY *
+replace_history_entry (which, line, data)
+ int which;
+ char *line;
+ char *data;
+{
+ HIST_ENTRY *temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+ HIST_ENTRY *old_value;
+
+ if (which >= history_length)
+ return ((HIST_ENTRY *)NULL);
+
+ old_value = the_history[which];
+
+ temp->line = savestring (line);
+ temp->data = data;
+ the_history[which] = temp;
+
+ return (old_value);
+}
+
+/* Returns the magic number which says what history element we are
+ looking at now. In this implementation, it returns history_offset. */
+int
+where_history ()
+{
+ return (history_offset);
+}
+
+/* Search the history for STRING, starting at history_offset.
+ If DIRECTION < 0, then the search is through previous entries,
+ else through subsequent. If the string is found, then
+ current_history () is the history entry, and the value of this function
+ is the offset in the line of that history entry that the string was
+ found in. Otherwise, nothing is changed, and a -1 is returned. */
+int
+history_search (string, direction)
+ char *string;
+ int direction;
+{
+ register int i = history_offset;
+ register int reverse = (direction < 0);
+ register char *line;
+ register int index;
+ int string_len = strlen (string);
+
+ /* Take care of trivial cases first. */
+
+ if (!history_length || (i == history_length) && !reverse)
+ return (-1);
+
+ if (reverse && (i == history_length))
+ i--;
+
+ while (1)
+ {
+ /* Search each line in the history list for STRING. */
+
+ /* At limit for direction? */
+ if ((reverse && i < 0) ||
+ (!reverse && i == history_length))
+ return (-1);
+
+ line = the_history[i]->line;
+ index = strlen (line);
+
+ /* If STRING is longer than line, no match. */
+ if (string_len > index)
+ goto next_line;
+
+ /* Do the actual search. */
+ if (reverse)
+ {
+ index -= string_len;
+
+ while (index >= 0)
+ {
+ if (strncmp (string, line + index, string_len) == 0)
+ {
+ history_offset = i;
+ return (index);
+ }
+ index--;
+ }
+ }
+ else
+ {
+ register int limit = (string_len - index) + 1;
+ index = 0;
+
+ while (index < limit)
+ {
+ if (strncmp (string, line + index, string_len) == 0)
+ {
+ history_offset = i;
+ return (index);
+ }
+ index++;
+ }
+ }
+ next_line:
+ if (reverse)
+ i--;
+ else
+ i++;
+ }
+}
+
+/* Remove history element WHICH from the history. The removed
+ element is returned to you so you can free the line, data,
+ and containing structure. */
+HIST_ENTRY *
+remove_history (which)
+ int which;
+{
+ HIST_ENTRY *return_value;
+
+ if (which >= history_length || !history_length)
+ return_value = (HIST_ENTRY *)NULL;
+ else
+ {
+ register int i;
+ return_value = the_history[which];
+
+ for (i = which; i < history_length; i++)
+ the_history[i] = the_history[i + 1];
+
+ history_length--;
+ }
+ return (return_value);
+}
+
+/* Stifle the history list, remembering only MAX number of lines. */
+void
+stifle_history (max)
+ int max;
+{
+ if (history_length > max)
+ {
+ register int i, j;
+
+ /* This loses because we cannot free the data. */
+ for (i = 0; i < (history_length - max); i++)
+ {
+ free (the_history[i]->line);
+ free (the_history[i]);
+ }
+ history_base = i;
+ for (j = 0, i = history_length - max; j < max; i++, j++)
+ the_history[j] = the_history[i];
+ the_history[j] = (HIST_ENTRY *)NULL;
+ history_length = j;
+ }
+ history_stifled = 1;
+ max_input_history = max;
+}
+
+/* Stop stifling the history. This returns the previous amount the history
+ was stifled by. The value is positive if the history was stifled, negative
+ if it wasn't. */
+int
+unstifle_history ()
+{
+ int result = max_input_history;
+ if (history_stifled)
+ {
+ result = - result;
+ history_stifled = 0;
+ }
+ return (result);
+}
+
+/* Return the string that should be used in the place of this
+ filename. This only matters when you don't specify the
+ filename to read_history (), or write_history (). */
+static char *
+history_filename (filename)
+ char *filename;
+{
+ char *return_val = filename ? savestring (filename) : (char *)NULL;
+
+ if (!return_val)
+ {
+ char *home = (char *)getenv ("HOME");
+ if (!home) home = ".";
+ return_val = (char *)xmalloc (2 + strlen (home) + strlen (".history"));
+ strcpy (return_val, home);
+ strcat (return_val, "/");
+ strcat (return_val, ".history");
+ }
+ return (return_val);
+}
+
+/* What to use until the line gets too big. */
+#define TYPICAL_LINE_SIZE 2048
+
+/* Add the contents of FILENAME to the history list, a line at a time.
+ If FILENAME is NULL, then read from ~/.history. Returns 0 if
+ successful, or errno if not. */
+int
+read_history (filename)
+ char *filename;
+{
+ char *input = history_filename (filename);
+ FILE *file = fopen (input, "r");
+ char *line = (char *)xmalloc (TYPICAL_LINE_SIZE);
+ int line_size = TYPICAL_LINE_SIZE;
+ int done = 0;
+
+ if (!file)
+ {
+ extern int errno;
+ free (line);
+ return (errno);
+ }
+
+ while (!done)
+ {
+ int c;
+ int i;
+
+ i = 0;
+ while (!(done = ((c = getc (file)) == EOF)))
+ {
+ if (c == '\n')
+ break;
+
+ line [i++] = c;
+ if (i == line_size)
+ line = (char *)xrealloc (line, line_size += TYPICAL_LINE_SIZE);
+ }
+ line[i] = '\0';
+ if (line[0])
+ add_history (line);
+ }
+ free (line);
+ fclose (file);
+ return (0);
+}
+
+/* Overwrite FILENAME with the current history. If FILENAME is NULL,
+ then write the history list to ~/.history. Values returned
+ are as in read_history ().*/
+int
+write_history (filename)
+ char *filename;
+{
+ extern int errno;
+ char *output = history_filename (filename);
+ FILE *file = fopen (output, "w");
+ register int i;
+
+ if (!file) return (errno);
+ if (!history_length) return (0);
+
+ for (i = 0; i < history_length; i++)
+ fprintf (file, "%s\n", the_history[i]->line);
+
+ fclose (file);
+ return (0);
+}
+
+/* Return the history entry at the current position, as determined by
+ history_offset. If there is no entry there, return a NULL pointer. */
+HIST_ENTRY *
+current_history ()
+{
+ if ((history_offset == history_length) || !the_history)
+ return ((HIST_ENTRY *)NULL);
+ else
+ return (the_history[history_offset]);
+}
+
+/* Back up history_offset to the previous history entry, and return
+ a pointer to that entry. If there is no previous entry then return
+ a NULL pointer. */
+HIST_ENTRY *
+previous_history ()
+{
+ if (!history_offset)
+ return ((HIST_ENTRY *)NULL);
+ else
+ return (the_history[--history_offset]);
+}
+
+/* Move history_offset forward to the next history entry, and return
+ a pointer to that entry. If there is no next entry then return a
+ NULL pointer. */
+HIST_ENTRY *
+next_history ()
+{
+ if (history_offset == history_length)
+ return ((HIST_ENTRY *)NULL);
+ else
+ return (the_history[++history_offset]);
+}
+
+/* Return the current history array. The caller has to be carefull, since this
+ is the actual array of data, and could be bashed or made corrupt easily.
+ The array is terminated with a NULL pointer. */
+HIST_ENTRY **
+history_list ()
+{
+ return (the_history);
+}
+
+/* Return the history entry which is logically at OFFSET in the history array.
+ OFFSET is relative to history_base. */
+HIST_ENTRY *
+history_get (offset)
+ int offset;
+{
+ int index = offset - history_base;
+
+ if (index >= history_length ||
+ index < 0 ||
+ !the_history)
+ return ((HIST_ENTRY *)NULL);
+ return (the_history[index]);
+}
+
+/* Search for STRING in the history list. DIR is < 0 for searching
+ backwards. POS is an absolute index into the history list at
+ which point to begin searching. */
+int
+history_search_pos (string, dir, pos)
+ char *string;
+ int dir, pos;
+{
+ int ret, old = where_history ();
+ history_set_pos (pos);
+ if (history_search (string, dir) == -1)
+ {
+ history_set_pos (old);
+ return (-1);
+ }
+ ret = where_history ();
+ history_set_pos (old);
+ return ret;
+}
+
+/* Make the current history item be the one at POS, an absolute index.
+ Returns zero if POS is out of range, else non-zero. */
+int
+history_set_pos (pos)
+ int pos;
+{
+ if (pos > history_length || pos < 0 || !the_history)
+ return (0);
+ history_offset = pos;
+ return (1);
+}
+
+
+/* **************************************************************** */
+/* */
+/* History Expansion */
+/* */
+/* **************************************************************** */
+
+/* Hairy history expansion on text, not tokens. This is of general
+ use, and thus belongs in this library. */
+
+/* The last string searched for in a !?string? search. */
+static char *search_string = (char *)NULL;
+
+/* Return the event specified at TEXT + OFFSET modifying OFFSET to
+ point to after the event specifier. Just a pointer to the history
+ line is returned; NULL is returned in the event of a bad specifier.
+ You pass STRING with *INDEX equal to the history_expansion_char that
+ begins this specification.
+ DELIMITING_QUOTE is a character that is allowed to end the string
+ specification for what to search for in addition to the normal
+ characters `:', ` ', `\t', `\n', and sometimes `?'.
+ So you might call this function like:
+ line = get_history_event ("!echo:p", &index, 0); */
+char *
+get_history_event (string, caller_index, delimiting_quote)
+ char *string;
+ int *caller_index;
+ int delimiting_quote;
+{
+ register int i = *caller_index;
+ int which, sign = 1;
+ HIST_ENTRY *entry;
+
+ /* The event can be specified in a number of ways.
+
+ !! the previous command
+ !n command line N
+ !-n current command-line minus N
+ !str the most recent command starting with STR
+ !?str[?]
+ the most recent command containing STR
+
+ All values N are determined via HISTORY_BASE. */
+
+ if (string[i] != history_expansion_char)
+ return ((char *)NULL);
+
+ /* Move on to the specification. */
+ i++;
+
+ /* Handle !! case. */
+ if (string[i] == history_expansion_char)
+ {
+ i++;
+ which = history_base + (history_length - 1);
+ *caller_index = i;
+ goto get_which;
+ }
+
+ /* Hack case of numeric line specification. */
+ read_which:
+ if (string[i] == '-')
+ {
+ sign = -1;
+ i++;
+ }
+
+ if (digit (string[i]))
+ {
+ int start = i;
+
+ /* Get the extent of the digits. */
+ for (; digit (string[i]); i++);
+
+ /* Get the digit value. */
+ sscanf (string + start, "%d", &which);
+
+ *caller_index = i;
+
+ if (sign < 0)
+ which = (history_length + history_base) - which;
+
+ get_which:
+ if (entry = history_get (which))
+ return (entry->line);
+
+ return ((char *)NULL);
+ }
+
+ /* This must be something to search for. If the spec begins with
+ a '?', then the string may be anywhere on the line. Otherwise,
+ the string must be found at the start of a line. */
+ {
+ int index;
+ char *temp;
+ int substring_okay = 0;
+
+ if (string[i] == '?')
+ {
+ substring_okay++;
+ i++;
+ }
+
+ for (index = i; string[i]; i++)
+ if (whitespace (string[i]) ||
+ string[i] == '\n' ||
+ string[i] == ':' ||
+ (substring_okay && string[i] == '?') ||
+ string[i] == delimiting_quote)
+ break;
+
+ temp = (char *)alloca (1 + (i - index));
+ strncpy (temp, &string[index], (i - index));
+ temp[i - index] = '\0';
+
+ if (string[i] == '?')
+ i++;
+
+ *caller_index = i;
+
+ search_again:
+
+ index = history_search (temp, -1);
+
+ if (index < 0)
+ search_lost:
+ {
+ history_offset = history_length;
+ return ((char *)NULL);
+ }
+
+ if (index == 0 || substring_okay ||
+ (strncmp (temp, the_history[history_offset]->line,
+ strlen (temp)) == 0))
+ {
+ search_won:
+ entry = current_history ();
+ history_offset = history_length;
+
+ /* If this was a substring search, then remember the string that
+ we matched for word substitution. */
+ if (substring_okay)
+ {
+ if (search_string)
+ free (search_string);
+ search_string = savestring (temp);
+ }
+
+ return (entry->line);
+ }
+
+ if (history_offset)
+ history_offset--;
+ else
+ goto search_lost;
+
+ goto search_again;
+ }
+}
+
+/* Expand the string STRING, placing the result into OUTPUT, a pointer
+ to a string. Returns:
+
+ 0) If no expansions took place (or, if the only change in
+ the text was the de-slashifying of the history expansion
+ character)
+ 1) If expansions did take place
+ -1) If there was an error in expansion.
+
+ If an error ocurred in expansion, then OUTPUT contains a descriptive
+ error message. */
+int
+history_expand (string, output)
+ char *string;
+ char **output;
+{
+ register int j, l = strlen (string);
+ int i, word_spec_error = 0;
+ int cc, modified = 0;
+ char *word_spec, *event;
+ int starting_index, only_printing = 0, substitute_globally = 0;
+
+ char *get_history_word_specifier (), *rindex ();
+
+ /* The output string, and its length. */
+ int len = 0;
+ char *result = (char *)NULL;
+
+ /* Used in add_string; */
+ char *temp, tt[2], tbl[3];
+
+ /* Prepare the buffer for printing error messages. */
+ result = (char *)xmalloc (len = 255);
+
+ result[0] = tt[1] = tbl[2] = '\0';
+ tbl[0] = '\\';
+ tbl[1] = history_expansion_char;
+
+ /* Grovel the string. Only backslash can quote the history escape
+ character. We also handle arg specifiers. */
+
+ /* Before we grovel forever, see if the history_expansion_char appears
+ anywhere within the text. */
+
+ /* The quick substitution character is a history expansion all right. That
+ is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
+ that is the substitution that we do. */
+ if (string[0] == history_subst_char)
+ {
+ char *format_string = (char *)alloca (10 + strlen (string));
+
+ sprintf (format_string, "%c%c:s%s",
+ history_expansion_char, history_expansion_char,
+ string);
+ string = format_string;
+ l += 4;
+ goto grovel;
+ }
+
+ /* If not quick substitution, still maybe have to do expansion. */
+
+ /* `!' followed by one of the characters in history_no_expand_chars
+ is NOT an expansion. */
+ for (i = 0; string[i]; i++)
+ if (string[i] == history_expansion_char)
+ if (!string[i + 1] || member (string[i + 1], history_no_expand_chars))
+ continue;
+ else
+ goto grovel;
+
+ free (result);
+ *output = savestring (string);
+ return (0);
+
+ grovel:
+
+ for (i = j = 0; i < l; i++)
+ {
+ int tchar = string[i];
+ if (tchar == history_expansion_char)
+ tchar = -3;
+
+ switch (tchar)
+ {
+ case '\\':
+ if (string[i + 1] == history_expansion_char)
+ {
+ i++;
+ temp = tbl;
+ goto do_add;
+ }
+ else
+ goto add_char;
+
+ /* case history_expansion_char: */
+ case -3:
+ starting_index = i + 1;
+ cc = string[i + 1];
+
+ /* If the history_expansion_char is followed by one of the
+ characters in history_no_expand_chars, then it is not a
+ candidate for expansion of any kind. */
+ if (member (cc, history_no_expand_chars))
+ goto add_char;
+
+ /* There is something that is listed as a `word specifier' in csh
+ documentation which means `the expanded text to this point'.
+ That is not a word specifier, it is an event specifier. */
+
+ if (cc == '#')
+ goto hack_pound_sign;
+
+ /* If it is followed by something that starts a word specifier,
+ then !! is implied as the event specifier. */
+
+ if (member (cc, ":$*%^"))
+ {
+ char fake_s[2];
+ int fake_i = 0;
+ i++;
+ fake_s[0] = fake_s[1] = history_expansion_char;
+ fake_s[2] = '\0';
+ event = get_history_event (fake_s, &fake_i);
+ }
+ else
+ {
+ int quoted_search_delimiter = 0;
+
+ /* If the character before this `!' is a double or single
+ quote, then this expansion takes place inside of the
+ quoted string. If we have to search for some text ("!foo"),
+ allow the delimiter to end the search string. */
+ if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
+ quoted_search_delimiter = string[i - 1];
+
+ event = get_history_event (string, &i, quoted_search_delimiter);
+ }
+
+ if (!event)
+ event_not_found:
+ {
+ int l = 1 + (i - starting_index);
+
+ temp = (char *)alloca (1 + l);
+ strncpy (temp, string + starting_index, l);
+ temp[l - 1] = 0;
+ sprintf (result, "%s: %s.", temp,
+ word_spec_error ? "Bad word specifier" : "Event not found");
+ error_exit:
+ *output = result;
+ return (-1);
+ }
+
+ /* If a word specifier is found, then do what that requires. */
+ starting_index = i;
+
+ word_spec = get_history_word_specifier (string, event, &i);
+
+ /* There is no such thing as a `malformed word specifier'. However,
+ it is possible for a specifier that has no match. In that case,
+ we complain. */
+ if (word_spec == (char *)-1)
+ bad_word_spec:
+ {
+ word_spec_error++;
+ goto event_not_found;
+ }
+
+ /* If no word specifier, than the thing of interest was the event. */
+ if (!word_spec)
+ temp = event;
+ else
+ {
+ temp = (char *)alloca (1 + strlen (word_spec));
+ strcpy (temp, word_spec);
+ free (word_spec);
+ }
+
+ /* Perhaps there are other modifiers involved. Do what they say. */
+
+ hack_specials:
+
+ if (string[i] == ':')
+ {
+ char *tstr;
+
+ switch (string[i + 1])
+ {
+ /* :p means make this the last executed line. So we
+ return an error state after adding this line to the
+ history. */
+ case 'p':
+ only_printing++;
+ goto next_special;
+
+ /* :t discards all but the last part of the pathname. */
+ case 't':
+ tstr = rindex (temp, '/');
+ if (tstr)
+ temp = ++tstr;
+ goto next_special;
+
+ /* :h discards the last part of a pathname. */
+ case 'h':
+ tstr = rindex (temp, '/');
+ if (tstr)
+ *tstr = '\0';
+ goto next_special;
+
+ /* :r discards the suffix. */
+ case 'r':
+ tstr = rindex (temp, '.');
+ if (tstr)
+ *tstr = '\0';
+ goto next_special;
+
+ /* :e discards everything but the suffix. */
+ case 'e':
+ tstr = rindex (temp, '.');
+ if (tstr)
+ temp = tstr;
+ goto next_special;
+
+ /* :s/this/that substitutes `this' for `that'. */
+ /* :gs/this/that substitutes `this' for `that' globally. */
+ case 'g':
+ if (string[i + 2] == 's')
+ {
+ i++;
+ substitute_globally = 1;
+ goto substitute;
+ }
+ else
+
+ case 's':
+ substitute:
+ {
+ char *this, *that, *new_event;
+ int delimiter = 0;
+ int si, l_this, l_that, l_temp = strlen (temp);
+
+ if (i + 2 < strlen (string))
+ delimiter = string[i + 2];
+
+ if (!delimiter)
+ break;
+
+ i += 3;
+
+ /* Get THIS. */
+ for (si = i; string[si] && string[si] != delimiter; si++);
+ l_this = (si - i);
+ this = (char *)alloca (1 + l_this);
+ strncpy (this, string + i, l_this);
+ this[l_this] = '\0';
+
+ i = si;
+ if (string[si])
+ i++;
+
+ /* Get THAT. */
+ for (si = i; string[si] && string[si] != delimiter; si++);
+ l_that = (si - i);
+ that = (char *)alloca (1 + l_that);
+ strncpy (that, string + i, l_that);
+ that[l_that] = '\0';
+
+ i = si;
+ if (string[si]) i++;
+
+ /* Ignore impossible cases. */
+ if (l_this > l_temp)
+ goto cant_substitute;
+
+ /* Find the first occurrence of THIS in TEMP. */
+ si = 0;
+ for (; (si + l_this) <= l_temp; si++)
+ if (strncmp (temp + si, this, l_this) == 0)
+ {
+ new_event =
+ (char *)alloca (1 + (l_that - l_this) + l_temp);
+ strncpy (new_event, temp, si);
+ strncpy (new_event + si, that, l_that);
+ strncpy (new_event + si + l_that,
+ temp + si + l_this,
+ l_temp - (si + l_this));
+ new_event[(l_that - l_this) + l_temp] = '\0';
+ temp = new_event;
+
+ if (substitute_globally)
+ {
+ si += l_that;
+ l_temp = strlen (temp);
+ substitute_globally++;
+ continue;
+ }
+
+ goto hack_specials;
+ }
+
+ cant_substitute:
+
+ if (substitute_globally > 1)
+ {
+ substitute_globally = 0;
+ goto hack_specials;
+ }
+
+ goto event_not_found;
+ }
+
+ /* :# is the line so far. Note that we have to
+ alloca () it since RESULT could be realloc ()'ed
+ below in add_string. */
+ case '#':
+ hack_pound_sign:
+ if (result)
+ {
+ temp = (char *)alloca (1 + strlen (result));
+ strcpy (temp, result);
+ }
+ else
+ temp = "";
+
+ next_special:
+ i += 2;
+ goto hack_specials;
+ }
+
+ }
+ /* Believe it or not, we have to back the pointer up by one. */
+ --i;
+ goto add_string;
+
+ /* A regular character. Just add it to the output string. */
+ default:
+ add_char:
+ tt[0] = string[i];
+ temp = tt;
+ goto do_add;
+
+ add_string:
+ modified++;
+
+ do_add:
+ j += strlen (temp);
+ while (j > len)
+ result = (char *)xrealloc (result, (len += 255));
+
+ strcpy (result + (j - strlen (temp)), temp);
+ }
+ }
+
+ *output = result;
+
+ if (only_printing)
+ {
+ add_history (result);
+ return (-1);
+ }
+
+ return (modified != 0);
+}
+
+/* Return a consed string which is the word specified in SPEC, and found
+ in FROM. NULL is returned if there is no spec. -1 is returned if
+ the word specified cannot be found. CALLER_INDEX is the offset in
+ SPEC to start looking; it is updated to point to just after the last
+ character parsed. */
+char *
+get_history_word_specifier (spec, from, caller_index)
+ char *spec, *from;
+ int *caller_index;
+{
+ register int i = *caller_index;
+ int first, last;
+ int expecting_word_spec = 0;
+ char *history_arg_extract ();
+
+ /* The range of words to return doesn't exist yet. */
+ first = last = 0;
+
+ /* If we found a colon, then this *must* be a word specification. If
+ it isn't, then it is an error. */
+ if (spec[i] == ':')
+ i++, expecting_word_spec++;
+
+ /* Handle special cases first. */
+
+ /* `%' is the word last searched for. */
+ if (spec[i] == '%')
+ {
+ *caller_index = i + 1;
+ if (search_string)
+ return (savestring (search_string));
+ else
+ return (savestring (""));
+ }
+
+ /* `*' matches all of the arguments, but not the command. */
+ if (spec[i] == '*')
+ {
+ *caller_index = i + 1;
+ return (history_arg_extract (1, '$', from));
+ }
+
+ /* `$' is last arg. */
+ if (spec[i] == '$')
+ {
+ *caller_index = i + 1;
+ return (history_arg_extract ('$', '$', from));
+ }
+
+ /* Try to get FIRST and LAST figured out. */
+ if (spec[i] == '-' || spec[i] == '^')
+ {
+ first = 1;
+ goto get_last;
+ }
+
+ get_first:
+ if (digit (spec[i]) && expecting_word_spec)
+ {
+ sscanf (spec + i, "%d", &first);
+ for (; digit (spec[i]); i++);
+ }
+ else
+ return ((char *)NULL);
+
+ get_last:
+ if (spec[i] == '^')
+ {
+ i++;
+ last = 1;
+ goto get_args;
+ }
+
+ if (spec[i] != '-')
+ {
+ last = first;
+ goto get_args;
+ }
+
+ i++;
+
+ if (digit (spec[i]))
+ {
+ sscanf (spec + i, "%d", &last);
+ for (; digit (spec[i]); i++);
+ }
+ else
+ if (spec[i] == '$')
+ {
+ i++;
+ last = '$';
+ }
+
+ get_args:
+ {
+ char *result = (char *)NULL;
+
+ *caller_index = i;
+
+ if (last >= first)
+ result = history_arg_extract (first, last, from);
+
+ if (result)
+ return (result);
+ else
+ return ((char *)-1);
+ }
+}
+
+/* Extract the args specified, starting at FIRST, and ending at LAST.
+ The args are taken from STRING. */
+char *
+history_arg_extract (first, last, string)
+ int first, last;
+ char *string;
+{
+ register int i, len;
+ char *result = (char *)NULL;
+ int size = 0, offset = 0;
+
+ char **history_tokenize (), **list;
+
+ if (!(list = history_tokenize (string)))
+ return ((char *)NULL);
+
+ for (len = 0; list[len]; len++);
+
+ if (last == '$')
+ last = len - 1;
+
+ if (first == '$')
+ first = len - 1;
+
+ last++;
+
+ if (first > len || last > len)
+ result = ((char *)NULL);
+ else {
+ for (i = first; i < last; i++)
+ {
+ int l = strlen (list[i]);
+
+ if (!result)
+ result = (char *)xmalloc ((size = (2 + l)));
+ else
+ result = (char *)xrealloc (result, (size += (2 + l)));
+ strcpy (result + offset, list[i]);
+ offset += l;
+ if (i + 1 < last)
+ {
+ strcpy (result + offset, " ");
+ offset++;
+ }
+ }
+ }
+
+ for (i = 0; i < len; i++)
+ free (list[i]);
+
+ free (list);
+
+ return (result);
+}
+
+#define slashify_in_quotes "\\`\"$"
+
+/* Return an array of tokens, much as the shell might. The tokens are
+ parsed out of STRING. */
+char **
+history_tokenize (string)
+ char *string;
+{
+ char **result = (char **)NULL;
+ register int i, start, result_index, size;
+ int len;
+
+ i = result_index = size = 0;
+
+ /* Get a token, and stuff it into RESULT. The tokens are split
+ exactly where the shell would split them. */
+ get_token:
+
+ /* Skip leading whitespace. */
+ for (; string[i] && whitespace(string[i]); i++);
+
+ start = i;
+
+ if (!string[i] || string[i] == history_comment_char)
+ return (result);
+
+ if (member (string[i], "()\n")) {
+ i++;
+ goto got_token;
+ }
+
+ if (member (string[i], "<>;&|")) {
+ int peek = string[i + 1];
+
+ if (peek == string[i]) {
+ if (peek == '<') {
+ if (string[1 + 2] == '-')
+ i++;
+ i += 2;
+ goto got_token;
+ }
+
+ if (member (peek, ">:&|")) {
+ i += 2;
+ goto got_token;
+ }
+ } else {
+ if ((peek == '&' &&
+ (string[i] == '>' || string[i] == '<')) ||
+ ((peek == '>') &&
+ (string[i] == '&'))) {
+ i += 2;
+ goto got_token;
+ }
+ }
+ i++;
+ goto got_token;
+ }
+
+ /* Get word from string + i; */
+ {
+ int delimiter = 0;
+
+ if (member (string[i], "\"'`"))
+ delimiter = string[i++];
+
+ for (;string[i]; i++) {
+
+ if (string[i] == '\\') {
+
+ if (string[i + 1] == '\n') {
+ i++;
+ continue;
+ } else {
+ if (delimiter != '\'')
+ if ((delimiter != '"') ||
+ (member (string[i], slashify_in_quotes))) {
+ i++;
+ continue;
+ }
+ }
+ }
+
+ if (delimiter && string[i] == delimiter) {
+ delimiter = 0;
+ continue;
+ }
+
+ if (!delimiter && (member (string[i], " \t\n;&()|<>")))
+ goto got_token;
+
+ if (!delimiter && member (string[i], "\"'`")) {
+ delimiter = string[i];
+ continue;
+ }
+ }
+ got_token:
+
+ len = i - start;
+ if (result_index + 2 >= size) {
+ if (!size)
+ result = (char **)xmalloc ((size = 10) * (sizeof (char *)));
+ else
+ result =
+ (char **)xrealloc (result, ((size += 10) * (sizeof (char *))));
+ }
+ result[result_index] = (char *)xmalloc (1 + len);
+ strncpy (result[result_index], string + start, len);
+ result[result_index][len] = '\0';
+ result_index++;
+ result[result_index] = (char *)NULL;
+ }
+ if (string[i])
+ goto get_token;
+
+ return (result);
+}
+
+#ifdef STATIC_MALLOC
+
+/* **************************************************************** */
+/* */
+/* xmalloc and xrealloc () */
+/* */
+/* **************************************************************** */
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ static memory_error_and_abort ();
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ static memory_error_and_abort ();
+ char *temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static
+memory_error_and_abort ()
+{
+ fprintf (stderr, "history: Out of virtual memory!\n");
+ abort ();
+}
+#endif /* STATIC_MALLOC */
+
+
+/* **************************************************************** */
+/* */
+/* Test Code */
+/* */
+/* **************************************************************** */
+#ifdef TEST
+main ()
+{
+ char line[1024], *t;
+ int done = 0;
+
+ line[0] = 0;
+
+ while (!done)
+ {
+ fprintf (stdout, "history%% ");
+ t = gets (line);
+
+ if (!t)
+ strcpy (line, "quit");
+
+ if (line[0])
+ {
+ char *expansion;
+ int result;
+
+ using_history ();
+
+ result = history_expand (line, &expansion);
+ strcpy (line, expansion);
+ free (expansion);
+ if (result)
+ fprintf (stderr, "%s\n", line);
+
+ if (result < 0)
+ continue;
+
+ add_history (line);
+ }
+
+ if (strcmp (line, "quit") == 0) done = 1;
+ if (strcmp (line, "save") == 0) write_history (0);
+ if (strcmp (line, "read") == 0) read_history (0);
+ if (strcmp (line, "list") == 0)
+ {
+ register HIST_ENTRY **the_list = history_list ();
+ register int i;
+
+ if (the_list)
+ for (i = 0; the_list[i]; i++)
+ fprintf (stdout, "%d: %s\n", i + history_base, the_list[i]->line);
+ }
+ if (strncmp (line, "delete", strlen ("delete")) == 0)
+ {
+ int which;
+ if ((sscanf (line + strlen ("delete"), "%d", &which)) == 1)
+ {
+ HIST_ENTRY *entry = remove_history (which);
+ if (!entry)
+ fprintf (stderr, "No such entry %d\n", which);
+ else
+ {
+ free (entry->line);
+ free (entry);
+ }
+ }
+ else
+ {
+ fprintf (stderr, "non-numeric arg given to `delete'\n");
+ }
+ }
+ }
+}
+
+#endif /* TEST */
+
+/*
+* Local variables:
+* compile-command: "gcc -g -DTEST -o history history.c"
+* end:
+*/
diff --git a/gnu/usr.bin/gdb/readline/history.h b/gnu/usr.bin/gdb/readline/history.h
new file mode 100644
index 0000000..0bac209
--- /dev/null
+++ b/gnu/usr.bin/gdb/readline/history.h
@@ -0,0 +1,108 @@
+/* History.h -- the names of functions that you can call in history. */
+
+typedef struct _hist_entry {
+ char *line;
+ char *data;
+} HIST_ENTRY;
+
+/* For convenience only. You set this when interpreting history commands.
+ It is the logical offset of the first history element. */
+extern int history_base;
+
+/* Begin a session in which the history functions might be used. This
+ just initializes the interactive variables. */
+extern void using_history ();
+
+/* Place STRING at the end of the history list.
+ The associated data field (if any) is set to NULL. */
+extern void add_history ();
+
+/* Returns the number which says what history element we are now
+ looking at. */
+extern int where_history ();
+
+/* Set the position in the history list to POS. */
+int history_set_pos ();
+
+/* Search for STRING in the history list, starting at POS, an
+ absolute index into the list. DIR, if negative, says to search
+ backwards from POS, else forwards.
+ Returns the absolute index of the history element where STRING
+ was found, or -1 otherwise. */
+extern int history_search_pos ();
+
+/* A reasonably useless function, only here for completeness. WHICH
+ is the magic number that tells us which element to delete. The
+ elements are numbered from 0. */
+extern HIST_ENTRY *remove_history ();
+
+/* Stifle the history list, remembering only MAX number of entries. */
+extern void stifle_history ();
+
+/* Stop stifling the history. This returns the previous amount the
+ history was stifled by. The value is positive if the history was
+ stifled, negative if it wasn't. */
+extern int unstifle_history ();
+
+/* Add the contents of FILENAME to the history list, a line at a time.
+ If FILENAME is NULL, then read from ~/.history. Returns 0 if
+ successful, or errno if not. */
+extern int read_history ();
+
+/* Append the current history to FILENAME. If FILENAME is NULL,
+ then append the history list to ~/.history. Values returned
+ are as in read_history (). */
+extern int write_history ();
+
+
+/* Make the history entry at WHICH have LINE and DATA. This returns
+ the old entry so you can dispose of the data. In the case of an
+ invalid WHICH, a NULL pointer is returned. */
+extern HIST_ENTRY *replace_history_entry ();
+
+/* Return the history entry at the current position, as determined by
+ history_offset. If there is no entry there, return a NULL pointer. */
+HIST_ENTRY *current_history ();
+
+/* Back up history_offset to the previous history entry, and return
+ a pointer to that entry. If there is no previous entry, return
+ a NULL pointer. */
+extern HIST_ENTRY *previous_history ();
+
+/* Move history_offset forward to the next item in the input_history,
+ and return the a pointer to that entry. If there is no next entry,
+ return a NULL pointer. */
+extern HIST_ENTRY *next_history ();
+
+/* Return a NULL terminated array of HIST_ENTRY which is the current input
+ history. Element 0 of this list is the beginning of time. If there
+ is no history, return NULL. */
+extern HIST_ENTRY **history_list ();
+
+/* Search the history for STRING, starting at history_offset.
+ If DIRECTION < 0, then the search is through previous entries,
+ else through subsequent. If the string is found, then
+ current_history () is the history entry, and the value of this function
+ is the offset in the line of that history entry that the string was
+ found in. Otherwise, nothing is changed, and a -1 is returned. */
+extern int history_search ();
+
+/* Expand the string STRING, placing the result into OUTPUT, a pointer
+ to a string. Returns:
+
+ 0) If no expansions took place (or, if the only change in
+ the text was the de-slashifying of the history expansion
+ character)
+ 1) If expansions did take place
+ -1) If there was an error in expansion.
+
+ If an error ocurred in expansion, then OUTPUT contains a descriptive
+ error message. */
+extern int history_expand ();
+
+/* Extract a string segment consisting of the FIRST through LAST
+ arguments present in STRING. Arguments are broken up as in
+ the shell. */
+extern char *history_arg_extract ();
+
+
diff --git a/gnu/usr.bin/gdb/readline/keymaps.c b/gnu/usr.bin/gdb/readline/keymaps.c
new file mode 100644
index 0000000..e0c5e39
--- /dev/null
+++ b/gnu/usr.bin/gdb/readline/keymaps.c
@@ -0,0 +1,172 @@
+/* keymaps.c -- Functions and keymaps for the GNU Readline library. */
+
+/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
+
+ This file is part of GNU Readline, a library for reading lines
+ of text with interactive input and history editing.
+
+ Readline is free software; you can 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.
+
+ Readline is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Readline; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "keymaps.h"
+#include "emacs_keymap.c"
+
+#ifdef VI_MODE
+#include "vi_keymap.c"
+#endif
+
+/* Remove these declarations when we have a complete libgnu.a. */
+#define STATIC_MALLOC
+#ifndef STATIC_MALLOC
+extern char *xmalloc (), *xrealloc ();
+#else
+static char *xmalloc (), *xrealloc ();
+#endif
+
+/* **************************************************************** */
+/* */
+/* Functions for manipulating Keymaps. */
+/* */
+/* **************************************************************** */
+
+
+/* Return a new, empty keymap.
+ Free it with free() when you are done. */
+Keymap
+rl_make_bare_keymap ()
+{
+ register int i;
+ Keymap keymap = (Keymap)xmalloc (128 * sizeof (KEYMAP_ENTRY));
+
+ for (i = 0; i < 128; i++)
+ {
+ keymap[i].type = ISFUNC;
+ keymap[i].function = (Function *)NULL;
+ }
+
+ for (i = 'A'; i < ('Z' + 1); i++)
+ {
+ keymap[i].type = ISFUNC;
+ keymap[i].function = rl_do_lowercase_version;
+ }
+
+ return (keymap);
+}
+
+/* Return a new keymap which is a copy of MAP. */
+Keymap
+rl_copy_keymap (map)
+ Keymap map;
+{
+ register int i;
+ Keymap temp = rl_make_bare_keymap ();
+
+ for (i = 0; i < 128; i++)
+ {
+ temp[i].type = map[i].type;
+ temp[i].function = map[i].function;
+ }
+ return (temp);
+}
+
+/* Return a new keymap with the printing characters bound to rl_insert,
+ the uppercase Meta characters bound to run their lowercase equivalents,
+ and the Meta digits bound to produce numeric arguments. */
+Keymap
+rl_make_keymap ()
+{
+ extern rl_insert (), rl_rubout (), rl_do_lowercase_version ();
+ extern rl_digit_argument ();
+ register int i;
+ Keymap newmap;
+
+ newmap = rl_make_bare_keymap ();
+
+ /* All printing characters are self-inserting. */
+ for (i = ' '; i < 126; i++)
+ newmap[i].function = rl_insert;
+
+ newmap[TAB].function = rl_insert;
+ newmap[RUBOUT].function = rl_rubout;
+
+ return (newmap);
+}
+
+/* Free the storage associated with MAP. */
+rl_discard_keymap (map)
+ Keymap (map);
+{
+ int i;
+
+ if (!map)
+ return;
+
+ for (i = 0; i < 128; i++)
+ {
+ switch (map[i].type)
+ {
+ case ISFUNC:
+ break;
+
+ case ISKMAP:
+ rl_discard_keymap ((Keymap)map[i].function);
+ break;
+
+ case ISMACR:
+ free ((char *)map[i].function);
+ break;
+ }
+ }
+}
+
+#ifdef STATIC_MALLOC
+
+/* **************************************************************** */
+/* */
+/* xmalloc and xrealloc () */
+/* */
+/* **************************************************************** */
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ static memory_error_and_abort ();
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ static memory_error_and_abort ();
+ char *temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static
+memory_error_and_abort ()
+{
+ fprintf (stderr, "readline: Out of virtual memory!\n");
+ abort ();
+}
+#endif /* STATIC_MALLOC */
diff --git a/gnu/usr.bin/gdb/readline/keymaps.h b/gnu/usr.bin/gdb/readline/keymaps.h
new file mode 100644
index 0000000..3c577b3
--- /dev/null
+++ b/gnu/usr.bin/gdb/readline/keymaps.h
@@ -0,0 +1,53 @@
+/* keymaps.h -- Manipulation of readline keymaps. */
+
+#ifndef _KEYMAPS_H_
+#define _KEYMAPS_H_
+
+#include <readline/chardefs.h>
+
+#ifndef __FUNCTION_DEF
+typedef int Function ();
+#define __FUNCTION_DEF
+#endif
+
+/* A keymap contains one entry for each key in the ASCII set.
+ Each entry consists of a type and a pointer.
+ POINTER is the address of a function to run, or the
+ address of a keymap to indirect through.
+ TYPE says which kind of thing POINTER is. */
+typedef struct _keymap_entry {
+ char type;
+ Function *function;
+} KEYMAP_ENTRY;
+
+/* I wanted to make the above structure contain a union of:
+ union { Function *function; struct _keymap_entry *keymap; } value;
+ but this made it impossible for me to create a static array.
+ Maybe I need C lessons. */
+
+typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[128];
+typedef KEYMAP_ENTRY *Keymap;
+
+/* The values that TYPE can have in a keymap entry. */
+#define ISFUNC 0
+#define ISKMAP 1
+#define ISMACR 2
+
+extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap;
+extern KEYMAP_ENTRY_ARRAY vi_insertion_keymap, vi_movement_keymap;
+
+/* Return a new, empty keymap.
+ Free it with free() when you are done. */
+Keymap rl_make_bare_keymap ();
+
+/* Return a new keymap which is a copy of MAP. */
+Keymap rl_copy_keymap ();
+
+/* Return a new keymap with the printing characters bound to rl_insert,
+ the lowercase Meta characters bound to run their equivalents, and
+ the Meta digits bound to produce numeric arguments. */
+Keymap rl_make_keymap ();
+
+#endif /* _KEYMAPS_H_ */
+
+
diff --git a/gnu/usr.bin/gdb/readline/readline.c b/gnu/usr.bin/gdb/readline/readline.c
new file mode 100644
index 0000000..3e8f9a3
--- /dev/null
+++ b/gnu/usr.bin/gdb/readline/readline.c
@@ -0,0 +1,5557 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)readline.c 6.4 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* readline.c -- a general facility for reading lines of input
+ with emacs style editing and completion. */
+
+/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
+
+ This file contains the Readline Library (the Library), a set of
+ routines for providing Emacs style line input to programs that ask
+ for it.
+
+ The Library is free software; you can 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.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Remove these declarations when we have a complete libgnu.a. */
+#define STATIC_MALLOC
+#ifndef STATIC_MALLOC
+extern char *xmalloc (), *xrealloc ();
+#else
+static char *xmalloc (), *xrealloc ();
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <string.h>
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#if defined (sparc) && defined (sun)
+#include <alloca.h>
+#endif
+#endif
+
+#define NEW_TTY_DRIVER
+#if defined (SYSV) || defined (hpux)
+#undef NEW_TTY_DRIVER
+#include <termio.h>
+#else
+#include <sgtty.h>
+#endif
+
+#include <errno.h>
+extern int errno;
+
+#include <setjmp.h>
+
+/* These next are for filename completion. Perhaps this belongs
+ in a different place. */
+#include <sys/stat.h>
+
+#include <pwd.h>
+#ifdef SYSV
+struct passwd *getpwuid (), *getpwent ();
+#endif
+
+#define HACK_TERMCAP_MOTION
+
+#ifndef SYSV
+#include <sys/dir.h>
+#else /* SYSV */
+#ifdef hpux
+#include <ndir.h>
+#else
+#include <dirent.h>
+#define direct dirent
+#define d_namlen d_reclen
+#endif /* hpux */
+#endif /* SYSV */
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#ifndef digit
+#define digit(c) ((c) >= '0' && (c) <= '9')
+#endif
+
+#ifndef isletter
+#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
+#endif
+
+#ifndef digit_value
+#define digit_value(c) ((c) - '0')
+#endif
+
+#ifndef member
+char *index ();
+#define member(c, s) ((c) ? index ((s), (c)) : 0)
+#endif
+
+#ifndef isident
+#define isident(c) ((isletter(c) || digit(c) || c == '_'))
+#endif
+
+#ifndef exchange
+#define exchange(x, y) {int temp = x; x = y; y = temp;}
+#endif
+
+static update_line ();
+static void output_character_function ();
+static delete_chars ();
+static start_insert ();
+static end_insert ();
+
+/* This typedef is equivalant to the one for Function; it allows us
+ to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
+typedef void SigHandler ();
+
+#ifdef SIGWINCH
+static void rl_handle_sigwinch ();
+static SigHandler *old_sigwinch = (SigHandler *)NULL;
+#endif
+
+/* If on, then readline handles signals in a way that doesn't screw. */
+/* #define HANDLE_SIGNALS */
+
+#if defined (SYSV)
+#ifdef HANDLE_SIGNALS
+#undef HANDLE_SIGNALS
+#endif
+#endif
+
+/* Stupid comparison routine for qsort () ing strings. */
+static int
+compare_strings (s1, s2)
+ char **s1, **s2;
+{
+ return (strcmp (*s1, *s2));
+}
+
+
+/* **************************************************************** */
+/* */
+/* Line editing input utility */
+/* */
+/* **************************************************************** */
+
+/* A pointer to the keymap that is currently in use.
+ By default, it is the standard emacs keymap. */
+Keymap keymap = emacs_standard_keymap;
+
+#define vi_mode 0
+#define emacs_mode 1
+
+/* The current style of editing. */
+int rl_editing_mode = emacs_mode;
+
+/* Non-zero if the previous command was a kill command. */
+static int last_command_was_kill = 0;
+
+/* The current value of the numeric argument specified by the user. */
+int rl_numeric_arg = 1;
+
+/* Non-zero if an argument was typed. */
+int rl_explicit_arg = 0;
+
+/* Temporary value used while generating the argument. */
+static int arg_sign = 1;
+
+/* Non-zero means we have been called at least once before. */
+static int rl_initialized = 0;
+
+/* If non-zero, this program is running in an EMACS buffer. */
+static char *running_in_emacs = (char *)NULL;
+
+/* The current offset in the current input line. */
+int rl_point;
+
+/* Mark in the current input line. */
+int rl_mark;
+
+/* Length of the current input line. */
+int rl_end;
+
+/* Make this non-zero to return the current input_line. */
+int rl_done;
+
+/* The last function executed by readline. */
+Function *rl_last_func = (Function *)NULL;
+
+/* Top level environment for readline_internal (). */
+static jmp_buf readline_top_level;
+
+/* The streams we interact with. */
+static FILE *in_stream, *out_stream;
+
+/* The names of the streams that we do input and output to. */
+FILE *rl_instream = stdin, *rl_outstream = stdout;
+
+/* Non-zero means echo characters as they are read. */
+int readline_echoing_p = 1;
+
+/* Current prompt. */
+char *rl_prompt;
+
+/* The number of characters read in order to type this complete command. */
+int rl_key_sequence_length = 0;
+
+/* If non-zero, then this is the address of a function to call just
+ before readline_internal () prints the first prompt. */
+Function *rl_startup_hook = (Function *)NULL;
+
+/* What we use internally. You should always refer to RL_LINE_BUFFER. */
+static char *the_line;
+
+/* The character that can generate an EOF. Really read from
+ the terminal driver... just defaulted here. */
+static int eof_char = CTRL ('D');
+
+/* Non-zero makes this the next keystroke to read. */
+int rl_pending_input = 0;
+
+/* Pointer to a useful terminal name. */
+char *rl_terminal_name = (char *)NULL;
+
+/* Line buffer and maintenence. */
+char *rl_line_buffer = (char *)NULL;
+static int rl_line_buffer_len = 0;
+#define DEFAULT_BUFFER_SIZE 256
+
+
+/* **************************************************************** */
+/* */
+/* Top Level Functions */
+/* */
+/* **************************************************************** */
+
+/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means
+ none. A return value of NULL means that EOF was encountered. */
+char *
+readline (prompt)
+ char *prompt;
+{
+ static rl_prep_terminal (), rl_deprep_terminal ();
+ char *readline_internal ();
+ char *value;
+
+ rl_prompt = prompt;
+
+ /* If we are at EOF return a NULL string. */
+ if (rl_pending_input == EOF)
+ {
+ rl_pending_input = 0;
+ return ((char *)NULL);
+ }
+
+ rl_initialize ();
+ rl_prep_terminal ();
+
+#ifdef SIGWINCH
+ old_sigwinch = (SigHandler *)signal (SIGWINCH, rl_handle_sigwinch);
+#endif
+
+#ifdef HANDLE_SIGNALS
+ rl_set_signals ();
+#endif
+
+ value = readline_internal ();
+ rl_deprep_terminal ();
+
+#ifdef SIGWINCH
+ signal (SIGWINCH, old_sigwinch);
+#endif
+
+#ifdef HANDLE_SIGNALS
+ rl_clear_signals ();
+#endif
+
+ return (value);
+}
+
+/* Read a line of input from the global rl_instream, doing output on
+ the global rl_outstream.
+ If rl_prompt is non-null, then that is our prompt. */
+char *
+readline_internal ()
+{
+ int lastc, c, eof_found;
+
+ in_stream = rl_instream; out_stream = rl_outstream;
+ lastc = eof_found = 0;
+
+ if (rl_startup_hook)
+ (*rl_startup_hook) ();
+
+ if (!readline_echoing_p)
+ {
+ if (rl_prompt) {
+ fprintf (out_stream, "%s", rl_prompt);
+ fflush(out_stream);
+ }
+ }
+ else
+ {
+ rl_on_new_line ();
+ rl_redisplay ();
+#ifdef VI_MODE
+ if (rl_editing_mode == vi_mode)
+ rl_vi_insertion_mode ();
+#endif /* VI_MODE */
+ }
+
+ while (!rl_done)
+ {
+ int lk = last_command_was_kill;
+ int code = setjmp (readline_top_level);
+
+ if (code)
+ rl_redisplay ();
+
+ if (!rl_pending_input)
+ {
+ /* Then initialize the argument and number of keys read. */
+ rl_init_argument ();
+ rl_key_sequence_length = 0;
+ }
+
+ c = rl_read_key ();
+
+ /* EOF typed to a non-blank line is a <NL>. */
+ if (c == EOF && rl_end)
+ c = NEWLINE;
+
+ /* The character eof_char typed to blank line, and not as the
+ previous character is interpreted as EOF. */
+ if (((c == eof_char && lastc != c) || c == EOF) && !rl_end)
+ {
+ eof_found = 1;
+ break;
+ }
+
+ lastc = c;
+ rl_dispatch (c, keymap);
+
+ /* If there was no change in last_command_was_kill, then no kill
+ has taken place. Note that if input is pending we are reading
+ a prefix command, so nothing has changed yet. */
+ if (!rl_pending_input)
+ {
+ if (lk == last_command_was_kill)
+ last_command_was_kill = 0;
+ }
+
+#ifdef VI_MODE
+ /* In vi mode, when you exit insert mode, the cursor moves back
+ over the previous character. We explicitly check for that here. */
+ if (rl_editing_mode == vi_mode && keymap == vi_movement_keymap)
+ rl_vi_check ();
+#endif
+
+ if (!rl_done)
+ rl_redisplay ();
+ }
+
+ /* Restore the original of this history line, iff the line that we
+ are editing was originally in the history, AND the line has changed. */
+ {
+ HIST_ENTRY *entry = current_history ();
+
+ if (entry && rl_undo_list)
+ {
+ char *temp = savestring (the_line);
+ rl_revert_line ();
+ entry = replace_history_entry (where_history (), the_line,
+ (HIST_ENTRY *)NULL);
+ free_history_entry (entry);
+
+ strcpy (the_line, temp);
+ free (temp);
+ }
+ }
+
+ /* At any rate, it is highly likely that this line has an undo list. Get
+ rid of it now. */
+ if (rl_undo_list)
+ free_undo_list ();
+
+ if (eof_found)
+ return (char *)NULL;
+ else
+ return (savestring (the_line));
+}
+
+
+/* Variables for keyboard macros. */
+
+/* The currently executing macro string. If this is non-zero,
+ then it is a malloc ()'ed string where input is coming from. */
+static char *executing_macro = (char *)NULL;
+
+/* The offset in the above string to the next character to be read. */
+static int executing_macro_index = 0;
+
+/* Non-zero means to save keys that we dispatch on in a kbd macro. */
+static int defining_kbd_macro = 0;
+
+/* The current macro string being built. Characters get stuffed
+ in here by add_macro_char (). */
+static char *current_macro = (char *)NULL;
+
+/* The size of the buffer allocated to current_macro. */
+static int current_macro_size = 0;
+
+/* The index at which characters are being added to current_macro. */
+static int current_macro_index = 0;
+
+/* A structure used to save nested macro strings.
+ It is a linked list of string/index for each saved macro. */
+struct saved_macro {
+ struct saved_macro *next;
+ char *string;
+ int index;
+};
+
+/* The list of saved macros. */
+struct saved_macro *macro_list = (struct saved_macro *)NULL;
+
+
+/* **************************************************************** */
+/* */
+/* Signal Handling */
+/* */
+/* **************************************************************** */
+
+#ifdef SIGWINCH
+static void
+rl_handle_sigwinch (sig, code, scp)
+ int sig, code;
+ struct sigcontext *scp;
+{
+ char *term = rl_terminal_name, *getenv ();
+
+ if (readline_echoing_p)
+ {
+ if (!term)
+ term = getenv ("TERM");
+ if (!term)
+ term = "dumb";
+ rl_reset_terminal (term);
+#ifdef NEVER
+ crlf ();
+ rl_forced_update_display ();
+#endif
+ }
+
+ if (old_sigwinch &&
+ old_sigwinch != (SigHandler *)SIG_IGN &&
+ old_sigwinch != (SigHandler *)SIG_DFL)
+ (*old_sigwinch)(sig, code, scp);
+}
+#endif /* SIGWINCH */
+
+#ifdef HANDLE_SIGNALS
+/* Interrupt handling. */
+static SigHandler *old_int = (SigHandler *)NULL,
+ *old_tstp = (SigHandler *)NULL,
+ *old_ttou = (SigHandler *)NULL,
+ *old_ttin = (SigHandler *)NULL,
+ *old_cont = (SigHandler *)NULL;
+
+/* Handle an interrupt character. */
+static void
+rl_signal_handler (sig, code, scp)
+ int sig, code;
+ struct sigcontext *scp;
+{
+ static rl_prep_terminal (), rl_deprep_terminal ();
+
+ switch (sig)
+ {
+ case SIGINT:
+ free_undo_list ();
+ rl_clear_message ();
+ rl_init_argument ();
+#ifdef SIGWINCH
+ signal (SIGWINCH, old_sigwinch);
+#endif
+
+#ifdef SIGTSTP
+ case SIGTSTP:
+ case SIGTTOU:
+ case SIGTTIN:
+#endif
+
+ rl_clean_up_for_exit ();
+ rl_deprep_terminal ();
+ rl_clear_signals ();
+ rl_pending_input = 0;
+
+ kill (getpid (), sig);
+ sigsetmask (0);
+
+ rl_prep_terminal ();
+ rl_set_signals ();
+ }
+}
+
+rl_set_signals ()
+{
+ old_int = (SigHandler *)signal (SIGINT, rl_signal_handler);
+
+ if (old_int == (SigHandler *)SIG_IGN)
+ signal (SIGINT, SIG_IGN);
+
+#ifdef SIGTSTP
+ old_tstp = (SigHandler *)signal (SIGTSTP, rl_signal_handler);
+ if (old_tstp == (SigHandler *)SIG_IGN)
+ signal (SIGTSTP, SIG_IGN);
+#endif
+#ifdef SIGTTOU
+ old_ttou = (SigHandler *)signal (SIGTTOU, rl_signal_handler);
+ old_ttin = (SigHandler *)signal (SIGTTIN, rl_signal_handler);
+#endif
+}
+
+rl_clear_signals ()
+{
+ signal (SIGINT, old_int);
+
+#ifdef SIGTSTP
+ signal (SIGTSTP, old_tstp);
+#endif
+#ifdef SIGTTOU
+ signal (SIGTTOU, old_ttou);
+ signal (SIGTTIN, old_ttin);
+#endif
+}
+#endif /* HANDLE_SIGNALS */
+
+
+
+/* **************************************************************** */
+/* */
+/* Character Input Buffering */
+/* */
+/* **************************************************************** */
+
+/* If the terminal was in xoff state when we got to it, then xon_char
+ contains the character that is supposed to start it again. */
+static int xon_char, xoff_state;
+static int pop_index = 0, push_index = 0, ibuffer_len = 511;
+static unsigned char ibuffer[512];
+
+/* Non-null means it is a pointer to a function to run while waiting for
+ character input. */
+Function *rl_event_hook = (Function *)NULL;
+
+#define any_typein (push_index != pop_index)
+
+/* Add KEY to the buffer of characters to be read. */
+rl_stuff_char (key)
+ int key;
+{
+ if (key == EOF)
+ {
+ key = NEWLINE;
+ rl_pending_input = EOF;
+ }
+ ibuffer[push_index++] = key;
+ if (push_index >= ibuffer_len)
+ push_index = 0;
+}
+
+/* Return the amount of space available in the
+ buffer for stuffing characters. */
+int
+ibuffer_space ()
+{
+ if (pop_index > push_index)
+ return (pop_index - push_index);
+ else
+ return (ibuffer_len - (push_index - pop_index));
+}
+
+/* Get a key from the buffer of characters to be read.
+ Result is KEY if there was a key, or -2 if there wasn't. */
+int
+rl_get_char ()
+{
+ int key;
+
+ if (push_index == pop_index)
+ return (-2);
+
+ key = ibuffer[pop_index++];
+
+ if (pop_index >= ibuffer_len)
+ pop_index = 0;
+
+ return (key);
+}
+
+/* Stuff KEY into the *front* of the input buffer.
+ Returns non-zero if successful, zero if there is
+ no space left in the buffer. */
+int
+rl_unget_char (key)
+ int key;
+{
+ if (ibuffer_space ())
+ {
+ pop_index--;
+ if (pop_index < 0)
+ pop_index = ibuffer_len - 1;
+ ibuffer[pop_index] = key;
+ return (1);
+ }
+ return (0);
+}
+
+
+
+static void
+rl_getc (stream)
+ FILE *stream;
+{
+ int result;
+ int nchar;
+ int tty = fileno(stream);
+ char buf[512]; /* XXX - must be at least as large as ibuffer */
+
+ while (1)
+ {
+ if (ioctl(tty, FIONREAD, &nchar) == -1)
+ nchar = sizeof(buf);
+ else if (nchar <= 0)
+ nchar = 1;
+ result = ibuffer_space();
+ if (nchar > result)
+ nchar = result;
+ result = read(tty, buf, nchar);
+ if (result > 0)
+ {
+ register char *cp = buf;
+
+ while (--result >= 0)
+ rl_stuff_char(*cp++);
+ return;
+ }
+ if (errno != EINTR)
+ {
+ rl_stuff_char(EOF);
+ return;
+ }
+ }
+}
+
+/* Read a key, including pending input. */
+int
+rl_read_key ()
+{
+ int c;
+
+ rl_key_sequence_length++;
+
+ if (rl_pending_input)
+ {
+ c = rl_pending_input;
+ rl_pending_input = 0;
+ }
+ else
+ {
+ static int next_macro_key ();
+
+ /* If input is coming from a macro, then use that. */
+ if (c = next_macro_key ())
+ return (c);
+
+ while ((c = rl_get_char()) == -2)
+ {
+ if (rl_event_hook)
+ {
+ (*rl_event_hook) ();
+ if ((c = rl_get_char()) != -2)
+ return (c);
+ }
+ rl_getc(in_stream);
+ }
+ }
+#ifdef TIOCSTART
+ /* Ugh. But I can't think of a better way. */
+ if (xoff_state && c == xon_char)
+ {
+ ioctl (fileno (in_stream), TIOCSTART, 0);
+ xoff_state = 0;
+ return rl_read_key ();
+ }
+#endif /* TIOCSTART */
+ return (c);
+}
+
+/* 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. */
+rl_dispatch (key, map)
+ register int key;
+ Keymap map;
+{
+ if (defining_kbd_macro)
+ {
+ static add_macro_char ();
+
+ add_macro_char (key);
+ }
+
+ if (key > 127 && key < 256)
+ {
+ if (map[ESC].type == ISKMAP)
+ {
+ map = (Keymap)map[ESC].function;
+ key -= 128;
+ rl_dispatch (key, map);
+ }
+ else
+ ding ();
+ return;
+ }
+
+ switch (map[key].type)
+ {
+ case ISFUNC:
+ {
+ Function *func = map[key].function;
+
+ if (func != (Function *)NULL)
+ {
+ /* Special case rl_do_lowercase_version (). */
+ if (func == rl_do_lowercase_version)
+ {
+ rl_dispatch (to_lower (key), map);
+ return;
+ }
+
+ (*map[key].function)(rl_numeric_arg * arg_sign, key);
+ }
+ else
+ {
+ ding ();
+ return;
+ }
+ }
+ break;
+
+ case ISKMAP:
+ if (map[key].function != (Function *)NULL)
+ {
+ int newkey;
+
+ rl_key_sequence_length++;
+ newkey = rl_read_key ();
+ rl_dispatch (newkey, (Keymap)map[key].function);
+ }
+ else
+ {
+ ding ();
+ return;
+ }
+ break;
+
+ case ISMACR:
+ if (map[key].function != (Function *)NULL)
+ {
+ static with_macro_input ();
+ char *macro = savestring ((char *)map[key].function);
+
+ with_macro_input (macro);
+ return;
+ }
+ break;
+ }
+
+ /* If we have input pending, then the last command was a prefix
+ command. Don't change the state of rl_last_func. */
+ if (!rl_pending_input)
+ rl_last_func = map[key].function;
+}
+
+
+/* **************************************************************** */
+/* */
+/* Hacking Keyboard Macros */
+/* */
+/* **************************************************************** */
+
+/* Set up to read subsequent input from STRING.
+ STRING is free ()'ed when we are done with it. */
+static
+with_macro_input (string)
+ char *string;
+{
+ static push_executing_macro ();
+
+ push_executing_macro ();
+ executing_macro = string;
+ executing_macro_index = 0;
+}
+
+/* Return the next character available from a macro, or 0 if
+ there are no macro characters. */
+static int
+next_macro_key ()
+{
+ if (!executing_macro)
+ return (0);
+
+ if (!executing_macro[executing_macro_index])
+ {
+ static pop_executing_macro ();
+
+ pop_executing_macro ();
+ return (next_macro_key ());
+ }
+
+ return (executing_macro[executing_macro_index++]);
+}
+
+/* Save the currently executing macro on a stack of saved macros. */
+static
+push_executing_macro ()
+{
+ struct saved_macro *saver;
+
+ saver = (struct saved_macro *)xmalloc (sizeof (struct saved_macro));
+ saver->next = macro_list;
+ saver->index = executing_macro_index;
+ saver->string = executing_macro;
+
+ macro_list = saver;
+}
+
+/* Discard the current macro, replacing it with the one
+ on the top of the stack of saved macros. */
+static
+pop_executing_macro ()
+{
+ if (executing_macro)
+ free (executing_macro);
+
+ executing_macro = (char *)NULL;
+ executing_macro_index = 0;
+
+ if (macro_list)
+ {
+ struct saved_macro *disposer = macro_list;
+ executing_macro = macro_list->string;
+ executing_macro_index = macro_list->index;
+ macro_list = macro_list->next;
+ free (disposer);
+ }
+}
+
+/* Add a character to the macro being built. */
+static
+add_macro_char (c)
+ int c;
+{
+ if (current_macro_index + 1 >= current_macro_size)
+ {
+ if (!current_macro)
+ current_macro = (char *)xmalloc (current_macro_size = 25);
+ else
+ current_macro =
+ (char *)xrealloc (current_macro, current_macro_size += 25);
+ }
+
+ current_macro[current_macro_index++] = c;
+ current_macro[current_macro_index] = '\0';
+}
+
+/* Begin defining a keyboard macro.
+ Keystrokes are recorded as they are executed.
+ End the definition with rl_end_kbd_macro ().
+ If a numeric argument was explicitly typed, then append this
+ definition to the end of the existing macro, and start by
+ re-executing the existing macro. */
+rl_start_kbd_macro (ignore1, ignore2)
+ int ignore1, ignore2;
+{
+ if (defining_kbd_macro)
+ rl_abort ();
+
+ if (rl_explicit_arg)
+ {
+ if (current_macro)
+ with_macro_input (savestring (current_macro));
+ }
+ else
+ current_macro_index = 0;
+
+ defining_kbd_macro = 1;
+}
+
+/* Stop defining a keyboard macro.
+ A numeric argument says to execute the macro right now,
+ that many times, counting the definition as the first time. */
+rl_end_kbd_macro (count, ignore)
+ int count, ignore;
+{
+ if (!defining_kbd_macro)
+ rl_abort ();
+
+ current_macro_index -= (rl_key_sequence_length - 1);
+ current_macro[current_macro_index] = '\0';
+
+ defining_kbd_macro = 0;
+
+ rl_call_last_kbd_macro (--count, 0);
+}
+
+/* Execute the most recently defined keyboard macro.
+ COUNT says how many times to execute it. */
+rl_call_last_kbd_macro (count, ignore)
+ int count, ignore;
+{
+ if (!current_macro)
+ rl_abort ();
+
+ while (count--)
+ with_macro_input (savestring (current_macro));
+}
+
+
+/* Non-zero means do not parse any lines other than comments and
+ parser directives. */
+static unsigned char parsing_conditionalized_out = 0;
+
+/* **************************************************************** */
+/* */
+/* Initializations */
+/* */
+/* **************************************************************** */
+
+/* Initliaze readline (and terminal if not already). */
+rl_initialize ()
+{
+ extern char *rl_display_prompt;
+
+ /* If we have never been called before, initialize the
+ terminal and data structures. */
+ if (!rl_initialized)
+ {
+ readline_initialize_everything ();
+ rl_initialized++;
+ }
+
+ /* Initalize the current line information. */
+ rl_point = rl_end = 0;
+ the_line = rl_line_buffer;
+ the_line[0] = 0;
+
+ /* We aren't done yet. We haven't even gotten started yet! */
+ rl_done = 0;
+
+ /* Tell the history routines what is going on. */
+ start_using_history ();
+
+ /* Make the display buffer match the state of the line. */
+ {
+ extern char *rl_display_prompt;
+ extern int forced_display;
+
+ rl_on_new_line ();
+
+ rl_display_prompt = rl_prompt ? rl_prompt : "";
+ forced_display = 1;
+ }
+
+ /* No such function typed yet. */
+ rl_last_func = (Function *)NULL;
+
+ /* Parsing of key-bindings begins in an enabled state. */
+ {
+ parsing_conditionalized_out = 0;
+ }
+}
+
+/* Initialize the entire state of the world. */
+readline_initialize_everything ()
+{
+ /* Find out if we are running in Emacs. */
+ running_in_emacs = (char *)getenv ("EMACS");
+
+ /* Allocate data structures. */
+ if (!rl_line_buffer)
+ rl_line_buffer =
+ (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE);
+
+ /* Initialize the terminal interface. */
+ init_terminal_io ((char *)NULL);
+
+ /* Bind tty characters to readline functions. */
+ readline_default_bindings ();
+
+ /* Initialize the function names. */
+ rl_initialize_funmap ();
+
+ /* Read in the init file. */
+ rl_read_init_file ((char *)NULL);
+
+ /* If the completion parser's default word break characters haven't
+ been set yet, then do so now. */
+ {
+ extern char *rl_completer_word_break_characters;
+ extern char *rl_basic_word_break_characters;
+
+ if (rl_completer_word_break_characters == (char *)NULL)
+ rl_completer_word_break_characters = rl_basic_word_break_characters;
+ }
+}
+
+/* If this system allows us to look at the values of the regular
+ input editing characters, then bind them to their readline
+ equivalents. */
+readline_default_bindings ()
+{
+#ifdef TIOCGETP
+ struct sgttyb ttybuff;
+ int tty = fileno (rl_instream);
+
+ if (ioctl (tty, TIOCGETP, &ttybuff) != -1)
+ {
+ int erase = ttybuff.sg_erase, kill = ttybuff.sg_kill;
+
+ if (erase != -1 && keymap[erase].type == ISFUNC)
+ keymap[erase].function = rl_rubout;
+
+ if (kill != -1 && keymap[kill].type == ISFUNC)
+ keymap[kill].function = rl_unix_line_discard;
+ }
+
+#ifdef TIOCGLTC
+ {
+ struct ltchars lt;
+
+ if (ioctl (tty, TIOCGLTC, &lt) != -1)
+ {
+ int erase = lt.t_werasc, nextc = lt.t_lnextc;
+
+ if (erase != -1 && keymap[erase].type == ISFUNC)
+ keymap[erase].function = rl_unix_word_rubout;
+
+ if (nextc != -1 && keymap[nextc].type == ISFUNC)
+ keymap[nextc].function = rl_quoted_insert;
+ }
+ }
+#endif /* TIOCGLTC */
+#endif /* TIOCGETP */
+}
+
+
+/* **************************************************************** */
+/* */
+/* Numeric Arguments */
+/* */
+/* **************************************************************** */
+
+/* Handle C-u style numeric args, as well as M--, and M-digits. */
+
+/* Add the current digit to the argument in progress. */
+rl_digit_argument (ignore, key)
+ int ignore, key;
+{
+ rl_pending_input = key;
+ rl_digit_loop ();
+}
+
+/* What to do when you abort reading an argument. */
+rl_discard_argument ()
+{
+ ding ();
+ rl_clear_message ();
+ rl_init_argument ();
+}
+
+/* Create a default argument. */
+rl_init_argument ()
+{
+ rl_numeric_arg = arg_sign = 1;
+ rl_explicit_arg = 0;
+}
+
+/* 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. */
+rl_universal_argument ()
+{
+ rl_numeric_arg *= 4;
+ rl_digit_loop ();
+}
+
+rl_digit_loop ()
+{
+ int key, c;
+ while (1)
+ {
+ rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg);
+ key = c = rl_read_key ();
+
+ if (keymap[c].type == ISFUNC &&
+ keymap[c].function == rl_universal_argument)
+ {
+ rl_numeric_arg *= 4;
+ continue;
+ }
+ c = UNMETA (c);
+ if (numeric (c))
+ {
+ if (rl_explicit_arg)
+ rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0');
+ else
+ rl_numeric_arg = (c - '0');
+ rl_explicit_arg = 1;
+ }
+ else
+ {
+ if (c == '-' && !rl_explicit_arg)
+ {
+ rl_numeric_arg = 1;
+ arg_sign = -1;
+ }
+ else
+ {
+ rl_clear_message ();
+ rl_dispatch (key, keymap);
+ return;
+ }
+ }
+ }
+}
+
+
+/* **************************************************************** */
+/* */
+/* Display stuff */
+/* */
+/* **************************************************************** */
+
+/* This is the stuff that is hard for me. I never seem to write good
+ display routines in C. Let's see how I do this time. */
+
+/* (PWP) Well... Good for a simple line updater, but totally ignores
+ the problems of input lines longer than the screen width.
+
+ update_line and the code that calls it makes a multiple line,
+ automatically wrapping line update. Carefull attention needs
+ to be paid to the vertical position variables.
+
+ handling of terminals with autowrap on (incl. DEC braindamage)
+ could be improved a bit. Right now I just cheat and decrement
+ screenwidth by one. */
+
+/* Keep two buffers; one which reflects the current contents of the
+ screen, and the other to draw what we think the new contents should
+ be. Then compare the buffers, and make whatever changes to the
+ screen itself that we should. Finally, make the buffer that we
+ just drew into be the one which reflects the current contents of the
+ screen, and place the cursor where it belongs.
+
+ Commands that want to can fix the display themselves, and then let
+ this function know that the display has been fixed by setting the
+ RL_DISPLAY_FIXED variable. This is good for efficiency. */
+
+/* Termcap variables: */
+extern char *term_up, *term_dc, *term_cr;
+extern int screenheight, screenwidth, terminal_can_insert;
+
+/* What YOU turn on when you have handled all redisplay yourself. */
+int rl_display_fixed = 0;
+
+/* The visible cursor position. If you print some text, adjust this. */
+int last_c_pos = 0;
+int last_v_pos = 0;
+
+/* The last left edge of text that was displayed. This is used when
+ doing horizontal scrolling. It shifts in thirds of a screenwidth. */
+static int last_lmargin = 0;
+
+/* The line display buffers. One is the line currently displayed on
+ the screen. The other is the line about to be displayed. */
+static char *visible_line = (char *)NULL;
+static char *invisible_line = (char *)NULL;
+
+/* Number of lines currently on screen minus 1. */
+int vis_botlin = 0;
+
+/* A buffer for `modeline' messages. */
+char msg_buf[128];
+
+/* Non-zero forces the redisplay even if we thought it was unnecessary. */
+int forced_display = 0;
+
+/* The stuff that gets printed out before the actual text of the line.
+ This is usually pointing to rl_prompt. */
+char *rl_display_prompt = (char *)NULL;
+
+/* Default and initial buffer size. Can grow. */
+static int line_size = 1024;
+
+/* Non-zero means to always use horizontal scrolling in line display. */
+int horizontal_scroll_mode = 0;
+
+/* I really disagree with this, but my boss (among others) insists that we
+ support compilers that don't work. I don't think we are gaining by doing
+ so; what is the advantage in producing better code if we can't use it? */
+/* The following two declarations belong inside the
+ function block, not here. */
+static void move_cursor_relative ();
+static void output_some_chars ();
+
+/* Basic redisplay algorithm. */
+rl_redisplay ()
+{
+ register int in, out, c, linenum;
+ register char *line = invisible_line;
+ int c_pos = 0;
+ int inv_botlin = 0; /* Number of lines in newly drawn buffer. */
+
+ extern int readline_echoing_p;
+
+ if (!readline_echoing_p)
+ return;
+
+ if (!rl_display_prompt)
+ rl_display_prompt = "";
+
+ if (!invisible_line)
+ {
+ visible_line = (char *)xmalloc (line_size);
+ invisible_line = (char *)xmalloc (line_size);
+ line = invisible_line;
+ for (in = 0; in < line_size; in++)
+ {
+ visible_line[in] = 0;
+ invisible_line[in] = 1;
+ }
+ rl_on_new_line ();
+ }
+
+ /* Draw the line into the buffer. */
+ c_pos = -1;
+
+ /* Mark the line as modified or not. We only do this for history
+ lines. */
+ out = 0;
+ if (current_history () && rl_undo_list)
+ {
+ line[out++] = '*';
+ line[out] = '\0';
+ }
+
+ /* If someone thought that the redisplay was handled, but the currently
+ visible line has a different modification state than the one about
+ to become visible, then correct the callers misconception. */
+ if (visible_line[0] != invisible_line[0])
+ rl_display_fixed = 0;
+
+ strncpy (line + out, rl_display_prompt, strlen (rl_display_prompt));
+ out += strlen (rl_display_prompt);
+ line[out] = '\0';
+
+ for (in = 0; in < rl_end; in++)
+ {
+ c = the_line[in];
+
+ if (out + 1 >= line_size)
+ {
+ line_size *= 2;
+ visible_line = (char *)xrealloc (visible_line, line_size);
+ invisible_line = (char *)xrealloc (invisible_line, line_size);
+ line = invisible_line;
+ }
+
+ if (in == rl_point)
+ c_pos = out;
+
+ if (c > 127)
+ {
+ line[out++] = 'M';
+ line[out++] = '-';
+ line[out++] = c - 128;
+ }
+#define DISPLAY_TABS
+#ifdef DISPLAY_TABS
+ else if (c == '\t')
+ {
+ register int newout = (out | (int)7) + 1;
+ while (out < newout)
+ line[out++] = ' ';
+ }
+#endif
+ else if (c < 32)
+ {
+ line[out++] = 'C';
+ line[out++] = '-';
+ line[out++] = c + 64;
+ }
+ else
+ line[out++] = c;
+ }
+ line[out] = '\0';
+ if (c_pos < 0)
+ c_pos = out;
+
+ /* PWP: now is when things get a bit hairy. The visible and invisible
+ line buffers are really multiple lines, which would wrap every
+ (screenwidth - 1) characters. Go through each in turn, finding
+ the changed region and updating it. The line order is top to bottom. */
+
+ /* If we can move the cursor up and down, then use multiple lines,
+ otherwise, let long lines display in a single terminal line, and
+ horizontally scroll it. */
+
+ if (!horizontal_scroll_mode && term_up && *term_up)
+ {
+ int total_screen_chars = (screenwidth * screenheight);
+
+ if (!rl_display_fixed || forced_display)
+ {
+ forced_display = 0;
+
+ /* If we have more than a screenful of material to display, then
+ only display a screenful. We should display the last screen,
+ not the first. I'll fix this in a minute. */
+ if (out >= total_screen_chars)
+ out = total_screen_chars - 1;
+
+ /* Number of screen lines to display. */
+ inv_botlin = out / screenwidth;
+
+ /* For each line in the buffer, do the updating display. */
+ for (linenum = 0; linenum <= inv_botlin; linenum++)
+ update_line (linenum > vis_botlin ? ""
+ : &visible_line[linenum * screenwidth],
+ &invisible_line[linenum * screenwidth],
+ linenum);
+
+ /* We may have deleted some lines. If so, clear the left over
+ blank ones at the bottom out. */
+ if (vis_botlin > inv_botlin)
+ {
+ char *tt;
+ for (; linenum <= vis_botlin; linenum++)
+ {
+ tt = &visible_line[linenum * screenwidth];
+ move_vert (linenum);
+ move_cursor_relative (0, tt);
+ clear_to_eol ((linenum == vis_botlin)?
+ strlen (tt) : screenwidth);
+ }
+ }
+ vis_botlin = inv_botlin;
+
+ /* Move the cursor where it should be. */
+ move_vert (c_pos / screenwidth);
+ move_cursor_relative (c_pos % screenwidth,
+ &invisible_line[(c_pos / screenwidth) * screenwidth]);
+ }
+ }
+ else /* Do horizontal scrolling. */
+ {
+ int lmargin;
+
+ /* Always at top line. */
+ last_v_pos = 0;
+
+ /* If the display position of the cursor would be off the edge
+ of the screen, start the display of this line at an offset that
+ leaves the cursor on the screen. */
+ if (c_pos - last_lmargin > screenwidth - 2)
+ lmargin = (c_pos / (screenwidth / 3) - 2) * (screenwidth / 3);
+ else if (c_pos - last_lmargin < 1)
+ lmargin = ((c_pos - 1) / (screenwidth / 3)) * (screenwidth / 3);
+ else
+ lmargin = last_lmargin;
+
+ /* If the first character on the screen isn't the first character
+ in the display line, indicate this with a special character. */
+ if (lmargin > 0)
+ line[lmargin] = '<';
+
+ if (lmargin + screenwidth < out)
+ line[lmargin + screenwidth - 1] = '>';
+
+ if (!rl_display_fixed || forced_display || lmargin != last_lmargin)
+ {
+ forced_display = 0;
+ update_line (&visible_line[last_lmargin],
+ &invisible_line[lmargin], 0);
+
+ move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]);
+ last_lmargin = lmargin;
+ }
+ }
+ fflush (out_stream);
+
+ /* Swap visible and non-visible lines. */
+ {
+ char *temp = visible_line;
+ visible_line = invisible_line;
+ invisible_line = temp;
+ rl_display_fixed = 0;
+ }
+}
+
+/* PWP: update_line() is based on finding the middle difference of each
+ line on the screen; vis:
+
+ /old first difference
+ /beginning of line | /old last same /old EOL
+ v v v v
+old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
+new: eddie> Oh, my little buggy says to me, as lurgid as
+ ^ ^ ^ ^
+ \beginning of line | \new last same \new end of line
+ \new first difference
+
+ All are character pointers for the sake of speed. Special cases for
+ no differences, as well as for end of line additions must be handeled.
+
+ Could be made even smarter, but this works well enough */
+static
+update_line (old, new, current_line)
+ register char *old, *new;
+ int current_line;
+{
+ register char *ofd, *ols, *oe, *nfd, *nls, *ne;
+ int lendiff, wsatend;
+
+ /* Find first difference. */
+ for (ofd = old, nfd = new;
+ (ofd - old < screenwidth) && *ofd && (*ofd == *nfd);
+ ofd++, nfd++)
+ ;
+
+ /* Move to the end of the screen line. */
+ for (oe = ofd; ((oe - old) < screenwidth) && *oe; oe++);
+ for (ne = nfd; ((ne - new) < screenwidth) && *ne; ne++);
+
+ /* If no difference, continue to next line. */
+ if (ofd == oe && nfd == ne)
+ return;
+
+ wsatend = 1; /* flag for trailing whitespace */
+ ols = oe - 1; /* find last same */
+ nls = ne - 1;
+ while ((*ols == *nls) && (ols > ofd) && (nls > nfd))
+ {
+ if (*ols != ' ')
+ wsatend = 0;
+ ols--;
+ nls--;
+ }
+
+ if (wsatend)
+ {
+ ols = oe;
+ nls = ne;
+ }
+ else if (*ols != *nls)
+ {
+ if (*ols) /* don't step past the NUL */
+ ols++;
+ if (*nls)
+ nls++;
+ }
+
+ move_vert (current_line);
+ move_cursor_relative (ofd - old, old);
+
+ /* if (len (new) > len (old)) */
+ lendiff = (nls - nfd) - (ols - ofd);
+
+ /* Insert (diff(len(old),len(new)) ch */
+ if (lendiff > 0)
+ {
+ if (terminal_can_insert)
+ {
+ extern char *term_IC;
+
+ /* Sometimes it is cheaper to print the characters rather than
+ use the terminal's capabilities. */
+ if ((2 * (ne - nfd)) < lendiff && (!term_IC || !*term_IC))
+ {
+ output_some_chars (nfd, (ne - nfd));
+ last_c_pos += (ne - nfd);
+ }
+ else
+ {
+ if (*ols)
+ {
+ start_insert (lendiff);
+ output_some_chars (nfd, lendiff);
+ last_c_pos += lendiff;
+ end_insert ();
+ }
+ else
+ {
+ /* At the end of a line the characters do not have to
+ be "inserted". They can just be placed on the screen. */
+ output_some_chars (nfd, lendiff);
+ last_c_pos += lendiff;
+ }
+ /* Copy (new) chars to screen from first diff to last match. */
+ if (((nls - nfd) - lendiff) > 0)
+ {
+ output_some_chars (&nfd[lendiff], ((nls - nfd) - lendiff));
+ last_c_pos += ((nls - nfd) - lendiff);
+ }
+ }
+ }
+ else
+ { /* cannot insert chars, write to EOL */
+ output_some_chars (nfd, (ne - nfd));
+ last_c_pos += (ne - nfd);
+ }
+ }
+ else /* Delete characters from line. */
+ {
+ /* If possible and inexpensive to use terminal deletion, then do so. */
+ if (term_dc && (2 * (ne - nfd)) >= (-lendiff))
+ {
+ if (lendiff)
+ delete_chars (-lendiff); /* delete (diff) characters */
+
+ /* Copy (new) chars to screen from first diff to last match */
+ if ((nls - nfd) > 0)
+ {
+ output_some_chars (nfd, (nls - nfd));
+ last_c_pos += (nls - nfd);
+ }
+ }
+ /* Otherwise, print over the existing material. */
+ else
+ {
+ output_some_chars (nfd, (ne - nfd));
+ last_c_pos += (ne - nfd);
+ clear_to_eol ((oe - old) - (ne - new));
+ }
+ }
+}
+
+/* (PWP) tell the update routines that we have moved onto a
+ new (empty) line. */
+rl_on_new_line ()
+{
+ if (visible_line)
+ visible_line[0] = '\0';
+
+ last_c_pos = last_v_pos = 0;
+ vis_botlin = last_lmargin = 0;
+}
+
+/* Actually update the display, period. */
+rl_forced_update_display ()
+{
+ if (visible_line)
+ {
+ register char *temp = visible_line;
+
+ while (*temp) *temp++ = '\0';
+ }
+ rl_on_new_line ();
+ forced_display++;
+ rl_redisplay ();
+}
+
+/* Move the cursor from last_c_pos to NEW, which are buffer indices.
+ DATA is the contents of the screen line of interest; i.e., where
+ the movement is being done. */
+static void
+move_cursor_relative (new, data)
+ int new;
+ char *data;
+{
+ register int i;
+ static void output_character_function ();
+
+ /* It may be faster to output a CR, and then move forwards instead
+ of moving backwards. */
+ if (new + 1 < last_c_pos - new)
+ {
+ tputs (term_cr, 1, output_character_function);
+ last_c_pos = 0;
+ }
+
+ if (last_c_pos == new) return;
+
+ if (last_c_pos < new)
+ {
+ /* Move the cursor forward. We do it by printing the command
+ to move the cursor forward if there is one, else print that
+ portion of the output buffer again. Which is cheaper? */
+
+ /* The above comment is left here for posterity. It is faster
+ to print one character (non-control) than to print a control
+ sequence telling the terminal to move forward one character.
+ That kind of control is for people who don't know what the
+ data is underneath the cursor. */
+#ifdef HACK_TERMCAP_MOTION
+ extern char *term_forward_char;
+
+ if (term_forward_char)
+ for (i = last_c_pos; i < new; i++)
+ tputs (term_forward_char, 1, output_character_function);
+ else
+ for (i = last_c_pos; i < new; i++)
+ putc (data[i], out_stream);
+#else
+ for (i = last_c_pos; i < new; i++)
+ putc (data[i], out_stream);
+#endif /* HACK_TERMCAP_MOTION */
+ }
+ else
+ backspace (last_c_pos - new);
+ last_c_pos = new;
+}
+
+/* PWP: move the cursor up or down. */
+move_vert (to)
+ int to;
+{
+ void output_character_function ();
+ register int delta, i;
+
+ if (last_v_pos == to) return;
+
+ if (to > screenheight)
+ return;
+
+ if ((delta = to - last_v_pos) > 0)
+ {
+ for (i = 0; i < delta; i++)
+ putc ('\n', out_stream);
+ tputs (term_cr, 1, output_character_function);
+ last_c_pos = 0; /* because crlf() will do \r\n */
+ }
+ else
+ { /* delta < 0 */
+ if (term_up && *term_up)
+ for (i = 0; i < -delta; i++)
+ tputs (term_up, 1, output_character_function);
+ }
+ last_v_pos = to; /* now to is here */
+}
+
+/* Physically print C on out_stream. This is for functions which know
+ how to optimize the display. */
+rl_show_char (c)
+ int c;
+{
+ if (c > 127)
+ {
+ fprintf (out_stream, "M-");
+ c -= 128;
+ }
+
+#ifdef DISPLAY_TABS
+ if (c < 32 && c != '\t')
+#else
+ if (c < 32)
+#endif
+ {
+
+ c += 64;
+ }
+
+ putc (c, out_stream);
+ fflush (out_stream);
+}
+
+#ifdef DISPLAY_TABS
+int
+rl_character_len (c, pos)
+ register int c, pos;
+{
+ if (c < ' ' || c > 126)
+ {
+ if (c == '\t')
+ return (((pos | (int)7) + 1) - pos);
+ else
+ return (3);
+ }
+ else
+ return (1);
+}
+#else
+int
+rl_character_len (c)
+ int c;
+{
+ if (c < ' ' || c > 126)
+ return (3);
+ else
+ return (1);
+}
+#endif /* DISPLAY_TAB */
+
+/* How to print things in the "echo-area". The prompt is treated as a
+ mini-modeline. */
+rl_message (string, arg1, arg2)
+ char *string;
+{
+ sprintf (msg_buf, string, arg1, arg2);
+ rl_display_prompt = msg_buf;
+ rl_redisplay ();
+}
+
+/* How to clear things from the "echo-area". */
+rl_clear_message ()
+{
+ rl_display_prompt = rl_prompt;
+ rl_redisplay ();
+}
+
+/* **************************************************************** */
+/* */
+/* Terminal and Termcap */
+/* */
+/* **************************************************************** */
+
+static char *term_buffer = (char *)NULL;
+static char *term_string_buffer = (char *)NULL;
+
+/* Non-zero means this terminal can't really do anything. */
+int dumb_term = 0;
+
+char PC;
+char *BC, *UP;
+
+/* Some strings to control terminal actions. These are output by tputs (). */
+char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace;
+
+int screenwidth, screenheight;
+
+/* Non-zero if we determine that the terminal can do character insertion. */
+int terminal_can_insert = 0;
+
+/* How to insert characters. */
+char *term_im, *term_ei, *term_ic, *term_ip, *term_IC;
+
+/* How to delete characters. */
+char *term_dc, *term_DC;
+
+#ifdef HACK_TERMCAP_MOTION
+char *term_forward_char;
+#endif /* HACK_TERMCAP_MOTION */
+
+/* How to go up a line. */
+char *term_up;
+
+/* Re-initialize the terminal considering that the TERM/TERMCAP variable
+ has changed. */
+rl_reset_terminal (terminal_name)
+ char *terminal_name;
+{
+ init_terminal_io (terminal_name);
+}
+
+init_terminal_io (terminal_name)
+ char *terminal_name;
+{
+ char *term = (terminal_name? terminal_name : (char *)getenv ("TERM"));
+ char *tgetstr (), *buffer;
+
+
+ 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)
+ {
+ dumb_term = 1;
+ return;
+ }
+
+ BC = tgetstr ("pc", &buffer);
+ PC = buffer ? *buffer : 0;
+
+ term_backspace = tgetstr ("le", &buffer);
+
+ term_cr = tgetstr ("cr", &buffer);
+ term_clreol = tgetstr ("ce", &buffer);
+ term_clrpag = tgetstr ("cl", &buffer);
+
+ if (!term_cr)
+ term_cr = "\r";
+
+#ifdef HACK_TERMCAP_MOTION
+ term_forward_char = tgetstr ("nd", &buffer);
+#endif /* HACK_TERMCAP_MOTION */
+
+ screenwidth = tgetnum ("co");
+ if (screenwidth <= 0)
+ screenwidth = 80;
+ screenwidth--; /* PWP: avoid autowrap bugs */
+
+ screenheight = tgetnum ("li");
+ if (screenheight <= 0)
+ screenheight = 24;
+
+ term_im = tgetstr ("im", &buffer);
+ term_ei = tgetstr ("ei", &buffer);
+ term_IC = tgetstr ("IC", &buffer);
+ term_ic = tgetstr ("ic", &buffer);
+ term_ip = tgetstr ("ip", &buffer);
+ term_IC = tgetstr ("IC", &buffer);
+
+ /* "An application program can assume that the terminal can do
+ character insertion if *any one of* the capabilities `IC',
+ `im', `ic' or `ip' is provided." */
+#ifdef notdef
+ /* XXX Circumvent broken code. */
+ terminal_can_insert = (term_IC || term_im || term_ic || term_ip);
+#endif
+
+ term_up = tgetstr ("up", &buffer);
+ term_dc = tgetstr ("dc", &buffer);
+ term_DC = tgetstr ("DC", &buffer);
+}
+
+/* A function for the use of tputs () */
+static void
+output_character_function (c)
+ int c;
+{
+ putc (c, out_stream);
+}
+
+/* Write COUNT characters from STRING to the output stream. */
+static void
+output_some_chars (string, count)
+ char *string;
+ int count;
+{
+ fwrite (string, 1, count, out_stream);
+}
+
+
+/* Delete COUNT characters from the display line. */
+static
+delete_chars (count)
+ int count;
+{
+ if (count > screenwidth)
+ return;
+
+ if (term_DC && *term_DC)
+ {
+ char *tgoto (), *buffer;
+ buffer = tgoto (term_DC, 0, count);
+ tputs (buffer, 1, output_character_function);
+ }
+ else
+ {
+ if (term_dc && *term_dc)
+ while (count--)
+ tputs (term_dc, 1, output_character_function);
+ }
+}
+
+/* Prepare to insert by inserting COUNT blank spaces. */
+static
+start_insert (count)
+ int count;
+{
+ if (term_im && *term_im)
+ tputs (term_im, 1, output_character_function);
+
+ if (term_IC && *term_IC &&
+ (count > 1 || !term_ic || !*term_ic))
+ {
+ char *tgoto (), *buffer;
+ buffer = tgoto (term_IC, 0, count);
+ tputs (buffer, 1, output_character_function);
+ }
+ else
+ {
+ if (term_ic && *term_ic)
+ while (count--)
+ tputs (term_ic, 1, output_character_function);
+ }
+}
+
+/* We are finished doing our insertion. Send ending string. */
+static
+end_insert ()
+{
+ if (term_ei && *term_ei)
+ tputs (term_ei, 1, output_character_function);
+}
+
+/* Move the cursor back. */
+backspace (count)
+ int count;
+{
+ register int i;
+
+ if (term_backspace)
+ for (i = 0; i < count; i++)
+ tputs (term_backspace, 1, output_character_function);
+ else
+ for (i = 0; i < count; i++)
+ putc ('\b', out_stream);
+}
+
+/* Move to the start of the next line. */
+crlf ()
+{
+ tputs (term_cr, 1, output_character_function);
+ putc ('\n', out_stream);
+}
+
+/* Clear to the end of the line. COUNT is the minimum
+ number of character spaces to clear, */
+clear_to_eol (count)
+ int count;
+{
+ if (term_clreol) {
+ tputs (term_clreol, 1, output_character_function);
+ } else {
+ register int i;
+ /* Do one more character space. */
+ count++;
+ for (i = 0; i < count; i++)
+ putc (' ', out_stream);
+ backspace (count);
+ }
+}
+
+
+/* **************************************************************** */
+/* */
+/* Saving and Restoring the TTY */
+/* */
+/* **************************************************************** */
+
+#ifdef NEW_TTY_DRIVER
+
+/* Standard flags, including ECHO. */
+static int original_tty_flags = 0;
+
+/* Local mode flags, like LPASS8. */
+static int local_mode_flags = 0;
+
+/* Terminal characters. This has C-s and C-q in it. */
+static struct tchars original_tchars;
+
+/* Local special characters. This has the interrupt characters in it. */
+static struct ltchars original_ltchars;
+
+/* We use this to get and set the tty_flags. */
+static struct sgttyb the_ttybuff;
+
+/* Put the terminal in CBREAK mode so that we can detect key presses. */
+static
+rl_prep_terminal ()
+{
+ int tty = fileno (rl_instream);
+
+ /* We always get the latest tty values. Maybe stty changed them. */
+
+ ioctl (tty, TIOCGETP, &the_ttybuff);
+ original_tty_flags = the_ttybuff.sg_flags;
+
+ readline_echoing_p = (original_tty_flags & ECHO);
+
+ /* If this terminal doesn't care how the 8th bit is used,
+ then we can use it for the meta-key.
+ We check by seeing if BOTH odd and even parity are allowed. */
+ if ((the_ttybuff.sg_flags & (ODDP | EVENP)) == (ODDP | EVENP))
+ {
+#ifdef PASS8
+ the_ttybuff.sg_flags |= PASS8;
+#endif
+
+#if defined (TIOCLGET) && defined (LPASS8)
+ {
+ int flags;
+ ioctl (tty, TIOCLGET, &flags);
+ local_mode_flags = flags;
+ flags |= LPASS8;
+ ioctl (tty, TIOCLSET, &flags);
+ }
+#endif
+ }
+
+#ifdef TIOCGETC
+ {
+ struct tchars temp;
+
+ ioctl (tty, TIOCGETC, &original_tchars);
+ bcopy (&original_tchars, &temp, sizeof (struct tchars));
+
+ /* Get rid of C-s and C-q.
+ We remember the value of startc (C-q) so that if the terminal is in
+ xoff state, the user can xon it by pressing that character. */
+ xon_char = temp.t_startc;
+ temp.t_stopc = -1;
+ temp.t_startc = -1;
+
+ /* If there is an XON character, bind it to restart the output. */
+ if (xon_char != -1)
+ rl_bind_key (xon_char, rl_restart_output);
+
+ /* If there is an EOF char, bind eof_char to it. */
+ if (temp.t_eofc != -1)
+ eof_char = temp.t_eofc;
+
+#ifdef NEVER
+ /* Get rid of C-\ and C-c. */
+ temp.t_intrc = temp.t_quitc = -1;
+#endif
+
+ ioctl (tty, TIOCSETC, &temp);
+ }
+#endif /* TIOCGETC */
+
+#ifdef TIOCGLTC
+ {
+ struct ltchars temp;
+
+ ioctl (tty, TIOCGLTC, &original_ltchars);
+ bcopy (&original_ltchars, &temp, sizeof (struct ltchars));
+
+ /* Make the interrupt keys go away. Just enough to make people happy. */
+ temp.t_dsuspc = -1; /* C-y */
+ temp.t_lnextc = -1; /* C-v */
+
+ ioctl (tty, TIOCSLTC, &temp);
+ }
+#endif /* TIOCGLTC */
+
+ the_ttybuff.sg_flags &= ~ECHO;
+ the_ttybuff.sg_flags |= CBREAK;
+ ioctl (tty, TIOCSETN, &the_ttybuff);
+}
+
+/* Restore the terminal to its original state. */
+static
+rl_deprep_terminal ()
+{
+ int tty = fileno (rl_instream);
+
+#if defined (TIOCLGET) && defined (LPASS8)
+ if ((the_ttybuff.sg_flags & (ODDP | EVENP)) == (ODDP | EVENP))
+ ioctl (tty, TIOCLSET, &local_mode_flags);
+#endif
+
+#ifdef TIOCSLTC
+ ioctl (tty, TIOCSLTC, &original_ltchars);
+#endif
+
+#ifdef TIOCSETC
+ ioctl (tty, TIOCSETC, &original_tchars);
+#endif
+
+ the_ttybuff.sg_flags = original_tty_flags;
+ ioctl (tty, TIOCSETN, &the_ttybuff);
+ readline_echoing_p = 1;
+}
+
+#else /* !defined (NEW_TTY_DRIVER) */
+static struct termio otio;
+
+static
+rl_prep_terminal ()
+{
+ int tty = fileno (rl_instream);
+ struct termio tio;
+
+ ioctl (tty, TCGETA, &tio);
+ ioctl (tty, TCGETA, &otio);
+
+ readline_echoing_p = (tio.c_lflag & ECHO);
+
+ tio.c_lflag &= ~(ICANON|ECHO);
+ tio.c_iflag &= ~(IXON|ISTRIP|INPCK);
+
+#ifndef HANDLE_SIGNALS
+ tio.c_lflag &= ~ISIG;
+#endif
+
+ tio.c_cc[VEOF] = 1; /* really: MIN */
+ tio.c_cc[VEOL] = 0; /* really: TIME */
+ ioctl (tty, TCSETAW,&tio);
+}
+
+static
+rl_deprep_terminal ()
+{
+ int tty = fileno (rl_instream);
+ ioctl (tty, TCSETAW, &otio);
+}
+#endif /* NEW_TTY_DRIVER */
+
+
+/* **************************************************************** */
+/* */
+/* Utility Functions */
+/* */
+/* **************************************************************** */
+
+/* Return 0 if C is not a member of the class of characters that belong
+ in words, or 1 if it is. */
+
+int allow_pathname_alphabetic_chars = 0;
+char *pathname_alphabetic_chars = "/-_=~.#$";
+
+int
+alphabetic (c)
+ int c;
+{
+ if (pure_alphabetic (c) || (numeric (c)))
+ return (1);
+
+ if (allow_pathname_alphabetic_chars)
+ return ((int)rindex (pathname_alphabetic_chars, c));
+ else
+ return (0);
+}
+
+/* Return non-zero if C is a numeric character. */
+int
+numeric (c)
+ int c;
+{
+ return (c >= '0' && c <= '9');
+}
+
+/* Ring the terminal bell. */
+int
+ding ()
+{
+ if (readline_echoing_p)
+ {
+ fprintf (stderr, "\007");
+ fflush (stderr);
+ }
+ return (-1);
+}
+
+/* How to abort things. */
+rl_abort ()
+{
+ ding ();
+ rl_clear_message ();
+ rl_init_argument ();
+ rl_pending_input = 0;
+
+ defining_kbd_macro = 0;
+ while (executing_macro)
+ pop_executing_macro ();
+
+ longjmp (readline_top_level, 1);
+}
+
+/* Return a copy of the string between FROM and TO.
+ FROM is inclusive, TO is not. */
+char *
+rl_copy (from, to)
+ int from, to;
+{
+ register int length;
+ char *copy;
+
+ /* Fix it if the caller is confused. */
+ if (from > to) {
+ int t = from;
+ from = to;
+ to = t;
+ }
+
+ length = to - from;
+ copy = (char *)xmalloc (1 + length);
+ strncpy (copy, the_line + from, length);
+ copy[length] = '\0';
+ return (copy);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Insert and Delete */
+/* */
+/* **************************************************************** */
+
+
+/* Insert a string of text into the line at point. This is the only
+ way that you should do insertion. rl_insert () calls this
+ function. */
+rl_insert_text (string)
+ char *string;
+{
+ extern int doing_an_undo;
+ register int i, l = strlen (string);
+ while (rl_end + l >= rl_line_buffer_len)
+ {
+ rl_line_buffer =
+ (char *)xrealloc (rl_line_buffer,
+ rl_line_buffer_len += DEFAULT_BUFFER_SIZE);
+ the_line = rl_line_buffer;
+ }
+
+ for (i = rl_end; i >= rl_point; i--)
+ the_line[i + l] = the_line[i];
+ strncpy (the_line + rl_point, string, l);
+
+ /* Remember how to undo this if we aren't undoing something. */
+ if (!doing_an_undo)
+ {
+ /* If possible and desirable, concatenate the undos. */
+ if ((strlen (string) == 1) &&
+ rl_undo_list &&
+ (rl_undo_list->what == UNDO_INSERT) &&
+ (rl_undo_list->end == rl_point) &&
+ (rl_undo_list->end - rl_undo_list->start < 20))
+ rl_undo_list->end++;
+ else
+ rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL);
+ }
+ rl_point += l;
+ rl_end += l;
+ the_line[rl_end] = '\0';
+}
+
+/* Delete the string between FROM and TO. FROM is
+ inclusive, TO is not. */
+rl_delete_text (from, to)
+ int from, to;
+{
+ extern int doing_an_undo;
+ register char *text;
+
+ /* Fix it if the caller is confused. */
+ if (from > to) {
+ int t = from;
+ from = to;
+ to = t;
+ }
+ text = rl_copy (from, to);
+ strncpy (the_line + from, the_line + to, rl_end - to);
+
+ /* Remember how to undo this delete. */
+ if (!doing_an_undo)
+ rl_add_undo (UNDO_DELETE, from, to, text);
+ else
+ free (text);
+
+ rl_end -= (to - from);
+ the_line[rl_end] = '\0';
+}
+
+
+/* **************************************************************** */
+/* */
+/* Readline character functions */
+/* */
+/* **************************************************************** */
+
+/* This is not a gap editor, just a stupid line input routine. No hair
+ is involved in writing any of the functions, and none should be. */
+
+/* Note that:
+
+ rl_end is the place in the string that we would place '\0';
+ i.e., it is always safe to place '\0' there.
+
+ rl_point is the place in the string where the cursor is. Sometimes
+ this is the same as rl_end.
+
+ Any command that is called interactively receives two arguments.
+ The first is a count: the numeric arg pased to this command.
+ The second is the key which invoked this command.
+*/
+
+
+/* **************************************************************** */
+/* */
+/* Movement Commands */
+/* */
+/* **************************************************************** */
+
+/* Note that if you `optimize' the display for these functions, you cannot
+ use said functions in other functions which do not do optimizing display.
+ I.e., you will have to update the data base for rl_redisplay, and you
+ might as well let rl_redisplay do that job. */
+
+/* Move forward COUNT characters. */
+rl_forward (count)
+ int count;
+{
+ if (count < 0)
+ rl_backward (-count);
+ else
+ while (count)
+ {
+#ifdef VI_MODE
+ if (rl_point == (rl_end - (rl_editing_mode == vi_mode)))
+#else
+ if (rl_point == rl_end)
+#endif
+ {
+ ding ();
+ return;
+ }
+ else
+ rl_point++;
+ --count;
+ }
+}
+
+/* Move backward COUNT characters. */
+rl_backward (count)
+ int count;
+{
+ if (count < 0)
+ rl_forward (-count);
+ else
+ while (count)
+ {
+ if (!rl_point)
+ {
+ ding ();
+ return;
+ }
+ else
+ --rl_point;
+ --count;
+ }
+}
+
+/* Move to the beginning of the line. */
+rl_beg_of_line ()
+{
+ rl_point = 0;
+}
+
+/* Move to the end of the line. */
+rl_end_of_line ()
+{
+ rl_point = rl_end;
+}
+
+/* Move forward a word. We do what Emacs does. */
+rl_forward_word (count)
+ int count;
+{
+ int c;
+
+ if (count < 0)
+ {
+ rl_backward_word (-count);
+ return;
+ }
+
+ while (count)
+ {
+ if (rl_point == rl_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 = the_line[rl_point];
+ if (!alphabetic (c))
+ {
+ while (++rl_point < rl_end)
+ {
+ c = the_line[rl_point];
+ if (alphabetic (c)) break;
+ }
+ }
+ if (rl_point == rl_end) return;
+ while (++rl_point < rl_end)
+ {
+ c = the_line[rl_point];
+ if (!alphabetic (c)) break;
+ }
+ --count;
+ }
+}
+
+/* Move backward a word. We do what Emacs does. */
+rl_backward_word (count)
+ int count;
+{
+ int c;
+
+ if (count < 0)
+ {
+ rl_forward_word (-count);
+ return;
+ }
+
+ while (count)
+ {
+ if (!rl_point)
+ return;
+
+ /* Like rl_forward_word (), except that we look at the characters
+ just before point. */
+
+ c = the_line[rl_point - 1];
+ if (!alphabetic (c))
+ {
+ while (--rl_point)
+ {
+ c = the_line[rl_point - 1];
+ if (alphabetic (c)) break;
+ }
+ }
+
+ while (rl_point)
+ {
+ c = the_line[rl_point - 1];
+ if (!alphabetic (c))
+ break;
+ else --rl_point;
+ }
+ --count;
+ }
+}
+
+/* Clear the current line. Numeric argument to C-l does this. */
+rl_refresh_line ()
+{
+ int curr_line = last_c_pos / screenwidth;
+
+ move_vert(curr_line);
+ move_cursor_relative (0, the_line); /* XXX is this right */
+ rl_forced_update_display ();
+ rl_display_fixed = 1;
+}
+
+/* C-l typed to a line without quoting clears the screen, and then reprints
+ the prompt and the current input line. Given a numeric arg, redraw only
+ the current line. */
+rl_clear_screen ()
+{
+ extern char *term_clrpag;
+ static void output_character_function ();
+
+ if (rl_explicit_arg)
+ {
+ rl_refresh_line ();
+ return;
+ }
+
+ if (term_clrpag)
+ tputs (term_clrpag, 1, output_character_function);
+ else
+ crlf ();
+
+ rl_forced_update_display ();
+ rl_display_fixed = 1;
+}
+
+
+/* **************************************************************** */
+/* */
+/* Text commands */
+/* */
+/* **************************************************************** */
+
+/* Insert the character C at the current location, moving point forward. */
+rl_insert (count, c)
+ int count, c;
+{
+ register int i;
+ char *string;
+
+ if (count <= 0)
+ return;
+
+ /* If we can optimize, then do it. But don't let people crash
+ readline because of extra large arguments. */
+ if (count > 1 && count < 1024)
+ {
+ string = (char *)alloca (1 + count);
+
+ for (i = 0; i < count; i++)
+ string[i] = c;
+
+ string[i] = '\0';
+ rl_insert_text (string);
+ return;
+ }
+
+ if (count > 1024)
+ {
+ int descreaser;
+
+ string = (char *)alloca (1024 + 1);
+
+ for (i = 0; i < 1024; i++)
+ string[i] = c;
+
+ while (count)
+ {
+ descreaser = (count > 1024 ? 1024 : count);
+ string[descreaser] = '\0';
+ rl_insert_text (string);
+ count -= descreaser;
+ }
+ return;
+ }
+
+ /* We are inserting a single character.
+ If there is pending input, then make a string of all of the
+ pending characters that are bound to rl_insert, and insert
+ them all. */
+ if (any_typein)
+ {
+ int slen, key = 0, t;
+
+ i = 0;
+ string = (char *)alloca (ibuffer_len + 1);
+ string[i++] = c;
+
+ while ((key = rl_get_char()) != -2 &&
+ (keymap[key].type == ISFUNC &&
+ keymap[key].function == rl_insert))
+ string[i++] = key;
+
+ if (key != -2)
+ rl_unget_char (key);
+
+ string[i] = '\0';
+ rl_insert_text (string);
+ return;
+ }
+ else
+ {
+ /* Inserting a single character. */
+ string = (char *)alloca (2);
+
+ string[1] = '\0';
+ string[0] = c;
+ rl_insert_text (string);
+ }
+}
+
+/* Insert the next typed character verbatim. */
+rl_quoted_insert (count)
+ int count;
+{
+ int c = rl_read_key (in_stream);
+ rl_insert (count, c);
+}
+
+/* Insert a tab character. */
+rl_tab_insert (count)
+ int count;
+{
+ rl_insert (count, '\t');
+}
+
+#ifdef VI_MODE
+/* Non-zero means enter insertion mode. */
+static vi_doing_insert = 0;
+#endif
+
+/* What to do when a NEWLINE is pressed. We accept the whole line.
+ KEY is the key that invoked this command. I guess it could have
+ meaning in the future. */
+rl_newline (count, key)
+ int count, key;
+{
+
+ rl_done = 1;
+
+#ifdef VI_MODE
+ {
+ if (vi_doing_insert)
+ {
+ rl_end_undo_group ();
+ vi_doing_insert = 0;
+ }
+ }
+#endif /* VI_MODE */
+
+ if (readline_echoing_p)
+ {
+ move_vert (vis_botlin);
+ vis_botlin = 0;
+ crlf ();
+ fflush (out_stream);
+ rl_display_fixed++;
+ }
+}
+
+rl_clean_up_for_exit ()
+{
+ if (readline_echoing_p)
+ {
+ move_vert (vis_botlin);
+ vis_botlin = 0;
+ fflush (out_stream);
+ rl_restart_output ();
+ }
+}
+
+/* What to do for some uppercase characters, like meta characters,
+ and some characters appearing in emacs_ctlx_keymap. This function
+ is just a stub, you bind keys to it and the code in rl_dispatch ()
+ is special cased. */
+rl_do_lowercase_version (ignore1, ignore2)
+ int ignore1, ignore2;
+{
+}
+
+/* Rubout the character behind point. */
+rl_rubout (count)
+ int count;
+{
+ if (count < 0)
+ {
+ rl_delete (-count);
+ return;
+ }
+
+ if (!rl_point)
+ {
+ ding ();
+ return;
+ }
+
+ if (count > 1)
+ {
+ int orig_point = rl_point;
+ rl_backward (count);
+ rl_kill_text (orig_point, rl_point);
+ }
+ else
+ {
+ int c = the_line[--rl_point];
+ rl_delete_text (rl_point, rl_point + 1);
+
+ if (rl_point == rl_end && alphabetic (c) && last_c_pos)
+ {
+ backspace (1);
+ putc (' ', out_stream);
+ backspace (1);
+ last_c_pos--;
+ rl_display_fixed++;
+ }
+ }
+}
+
+/* Delete the character under the cursor. Given a numeric argument,
+ kill that many characters instead. */
+rl_delete (count, invoking_key)
+ int count;
+{
+ if (count < 0)
+ {
+ rl_rubout (-count);
+ return;
+ }
+
+ if (rl_point == rl_end)
+ {
+ ding ();
+ return;
+ }
+
+#ifdef VI_MODE
+ if ((count > 1) || ((count == 1) && (rl_editing_mode == vi_mode)))
+#else
+ if (count > 1)
+#endif
+ {
+ int orig_point = rl_point;
+ while (count && (rl_point < rl_end))
+ {
+ rl_point++;
+ count--;
+ }
+ rl_kill_text (orig_point, rl_point);
+ rl_point = orig_point;
+ }
+ else
+ rl_delete_text (rl_point, rl_point + 1);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Kill commands */
+/* */
+/* **************************************************************** */
+
+/* The next two functions mimic unix line editing behaviour, except they
+ save the deleted text on the kill ring. This is safer than not saving
+ it, and since we have a ring, nobody should get screwed. */
+
+/* This does what C-w does in Unix. We can't prevent people from
+ using behaviour that they expect. */
+rl_unix_word_rubout ()
+{
+ if (!rl_point) ding ();
+ else {
+ int orig_point = rl_point;
+ while (rl_point && whitespace (the_line[rl_point - 1]))
+ rl_point--;
+ while (rl_point && !whitespace (the_line[rl_point - 1]))
+ rl_point--;
+ rl_kill_text (rl_point, orig_point);
+ }
+}
+
+/* Here is C-u doing what Unix does. You don't *have* to use these
+ key-bindings. We have a choice of killing the entire line, or
+ killing from where we are to the start of the line. We choose the
+ latter, because if you are a Unix weenie, then you haven't backspaced
+ into the line at all, and if you aren't, then you know what you are
+ doing. */
+rl_unix_line_discard ()
+{
+ if (!rl_point) ding ();
+ else {
+ rl_kill_text (rl_point, 0);
+ rl_point = 0;
+ }
+}
+
+
+
+/* **************************************************************** */
+/* */
+/* Commands For Typos */
+/* */
+/* **************************************************************** */
+
+/* Random and interesting things in here. */
+
+
+/* **************************************************************** */
+/* */
+/* Changing Case */
+/* */
+/* **************************************************************** */
+
+/* The three kinds of things that we know how to do. */
+#define UpCase 1
+#define DownCase 2
+#define CapCase 3
+
+/* Uppercase the word at point. */
+rl_upcase_word (count)
+ int count;
+{
+ rl_change_case (count, UpCase);
+}
+
+/* Lowercase the word at point. */
+rl_downcase_word (count)
+ int count;
+{
+ rl_change_case (count, DownCase);
+}
+
+/* Upcase the first letter, downcase the rest. */
+rl_capitalize_word (count)
+ int count;
+{
+ rl_change_case (count, CapCase);
+}
+
+/* The meaty function.
+ Change the case of COUNT words, performing OP on them.
+ OP is one of UpCase, DownCase, or CapCase.
+ If a negative argument is given, leave point where it started,
+ otherwise, leave it where it moves to. */
+rl_change_case (count, op)
+ int count, op;
+{
+ register int start = rl_point, end;
+ int state = 0;
+
+ rl_forward_word (count);
+ end = rl_point;
+
+ if (count < 0)
+ {
+ int temp = start;
+ start = end;
+ end = temp;
+ }
+
+ /* We are going to modify some text, so let's prepare to undo it. */
+ rl_modifying (start, end);
+
+ for (; start < end; start++)
+ {
+ switch (op)
+ {
+ case UpCase:
+ the_line[start] = to_upper (the_line[start]);
+ break;
+
+ case DownCase:
+ the_line[start] = to_lower (the_line[start]);
+ break;
+
+ case CapCase:
+ if (state == 0)
+ {
+ the_line[start] = to_upper (the_line[start]);
+ state = 1;
+ }
+ else
+ {
+ the_line[start] = to_lower (the_line[start]);
+ }
+ if (!pure_alphabetic (the_line[start]))
+ state = 0;
+ break;
+
+ default:
+ abort ();
+ }
+ }
+ rl_point = end;
+}
+
+/* **************************************************************** */
+/* */
+/* Transposition */
+/* */
+/* **************************************************************** */
+
+/* Transpose the words at point. */
+rl_transpose_words (count)
+ int count;
+{
+ char *word1, *word2;
+ int w1_beg, w1_end, w2_beg, w2_end;
+ int orig_point = rl_point;
+
+ if (!count) return;
+
+ /* Find the two words. */
+ rl_forward_word (count);
+ w2_end = rl_point;
+ rl_backward_word (1);
+ w2_beg = rl_point;
+ rl_backward_word (count);
+ w1_beg = rl_point;
+ rl_forward_word (1);
+ w1_end = rl_point;
+
+ /* Do some check to make sure that there really are two words. */
+ if ((w1_beg == w2_beg) || (w2_beg < w1_end))
+ {
+ ding ();
+ rl_point = orig_point;
+ return;
+ }
+
+ /* Get the text of the words. */
+ word1 = rl_copy (w1_beg, w1_end);
+ word2 = rl_copy (w2_beg, w2_end);
+
+ /* We are about to do many insertions and deletions. Remember them
+ as one operation. */
+ rl_begin_undo_group ();
+
+ /* Do the stuff at word2 first, so that we don't have to worry
+ about word1 moving. */
+ rl_point = w2_beg;
+ rl_delete_text (w2_beg, w2_end);
+ rl_insert_text (word1);
+
+ rl_point = w1_beg;
+ rl_delete_text (w1_beg, w1_end);
+ rl_insert_text (word2);
+
+ /* This is exactly correct since the text before this point has not
+ changed in length. */
+ rl_point = w2_end;
+
+ /* I think that does it. */
+ rl_end_undo_group ();
+ free (word1); free (word2);
+}
+
+/* Transpose the characters at point. If point is at the end of the line,
+ then transpose the characters before point. */
+rl_transpose_chars (count)
+ int count;
+{
+ if (!count)
+ return;
+
+ if (!rl_point || rl_end < 2) {
+ ding ();
+ return;
+ }
+
+ while (count) {
+ if (rl_point == rl_end) {
+ int t = the_line[rl_point - 1];
+ the_line[rl_point - 1] = the_line[rl_point - 2];
+ the_line[rl_point - 2] = t;
+ } else {
+ int t = the_line[rl_point];
+ the_line[rl_point] = the_line[rl_point - 1];
+ the_line[rl_point - 1] = t;
+ if (count < 0 && rl_point)
+ rl_point--;
+ else
+ rl_point++;
+ }
+ if (count < 0)
+ count++;
+ else
+ count--;
+ }
+}
+
+
+/* **************************************************************** */
+/* */
+/* Bogus Flow Control */
+/* */
+/* **************************************************************** */
+
+rl_restart_output (count, key)
+ int count, key;
+{
+ int fildes = fileno (stdin);
+#ifdef TIOCSTART
+ ioctl (fildes, TIOCSTART, 0);
+#endif /* TIOCSTART */
+}
+
+/* **************************************************************** */
+/* */
+/* Completion matching, from readline's point of view. */
+/* */
+/* **************************************************************** */
+
+/* Pointer to the generator function for completion_matches ().
+ NULL means to use filename_entry_function (), the default filename
+ completer. */
+Function *rl_completion_entry_function = (Function *)NULL;
+
+/* Pointer to alternative function to create matches.
+ Function is called with TEXT, START, and END.
+ START and END are indices in RL_LINE_BUFFER saying what the boundaries
+ of TEXT are.
+ If this function exists and returns NULL then call the value of
+ rl_completion_entry_function to try to match, otherwise use the
+ array of strings returned. */
+Function *rl_attempted_completion_function = (Function *)NULL;
+
+/* Complete the word at or before point. You have supplied the function
+ that does the initial simple matching selection algorithm (see
+ completion_matches ()). The default is to do filename completion. */
+rl_complete (ignore, invoking_key)
+ int ignore, invoking_key;
+{
+ rl_complete_internal (TAB);
+ if (running_in_emacs)
+ printf ("%s", the_line);
+}
+
+/* List the possible completions. See description of rl_complete (). */
+rl_possible_completions ()
+{
+ rl_complete_internal ('?');
+}
+
+/* The user must press "y" or "n". Non-zero return means "y" pressed. */
+get_y_or_n ()
+{
+ int c;
+ loop:
+ c = rl_read_key (in_stream);
+ if (c == 'y' || c == 'Y') return (1);
+ if (c == 'n' || c == 'N') return (0);
+ if (c == ABORT_CHAR) rl_abort ();
+ ding (); goto loop;
+}
+
+/* Up to this many items will be displayed in response to a
+ possible-completions call. After that, we ask the user if
+ she is sure she wants to see them all. */
+int rl_completion_query_items = 100;
+
+/* The basic list of characters that signal a break between words for the
+ completer routine. The contents of this variable is what breaks words
+ in the shell, i.e. " \t\n\"\\'`@$><=" */
+char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=";
+
+/* The list of characters that signal a break between words for
+ rl_complete_internal. The default list is the contents of
+ rl_basic_word_break_characters. */
+char *rl_completer_word_break_characters = (char *)NULL;
+
+/* List of characters that are word break characters, but should be left
+ in TEXT when it is passed to the completion function. The shell uses
+ this to help determine what kind of completing to do. */
+char *rl_special_prefixes = (char *)NULL;
+
+/* If non-zero, then disallow duplicates in the matches. */
+int rl_ignore_completion_duplicates = 1;
+
+/* Non-zero means that the results of the matches are to be treated
+ as filenames. This is ALWAYS zero on entry, and can only be changed
+ within a completion entry finder function. */
+int rl_filename_completion_desired = 0;
+
+/* Complete the word at or before point.
+ WHAT_TO_DO says what to do with the completion.
+ `?' means list the possible completions.
+ TAB means do standard completion.
+ `*' means insert all of the possible completions. */
+rl_complete_internal (what_to_do)
+ int what_to_do;
+{
+ char *filename_completion_function ();
+ char **completion_matches (), **matches;
+ Function *our_func;
+ int start, end, delimiter = 0;
+ char *text;
+
+ if (rl_completion_entry_function)
+ our_func = rl_completion_entry_function;
+ else
+ our_func = (int (*)())filename_completion_function;
+
+ /* Only the completion entry function can change this. */
+ rl_filename_completion_desired = 0;
+
+ /* We now look backwards for the start of a filename/variable word. */
+ end = rl_point;
+ if (rl_point)
+ {
+ while (--rl_point &&
+ !rindex (rl_completer_word_break_characters, the_line[rl_point]));
+
+ /* If we are at a word break, then advance past it. */
+ if (rindex (rl_completer_word_break_characters, (the_line[rl_point])))
+ {
+ /* If the character that caused the word break was a quoting
+ character, then remember it as the delimiter. */
+ if (rindex ("\"'", the_line[rl_point]) && (end - rl_point) > 1)
+ delimiter = the_line[rl_point];
+
+ /* If the character isn't needed to determine something special
+ about what kind of completion to perform, then advance past it. */
+
+ if (!rl_special_prefixes ||
+ !rindex (rl_special_prefixes, the_line[rl_point]))
+ rl_point++;
+ }
+ }
+
+ start = rl_point;
+ rl_point = end;
+ text = rl_copy (start, end);
+
+ /* If the user wants to TRY to complete, but then wants to give
+ up and use the default completion function, they set the
+ variable rl_attempted_completion_function. */
+ if (rl_attempted_completion_function)
+ {
+ matches =
+ (char **)(*rl_attempted_completion_function) (text, start, end);
+
+ if (matches)
+ goto after_usual_completion;
+ }
+
+ matches = completion_matches (text, our_func, start, end);
+
+ after_usual_completion:
+ free (text);
+
+ if (!matches)
+ ding ();
+ else
+ {
+ register int i;
+
+ some_matches:
+
+ /* It seems to me that in all the cases we handle we would like
+ to ignore duplicate possiblilities. Scan for the text to
+ insert being identical to the other completions. */
+ if (rl_ignore_completion_duplicates)
+ {
+ char *lowest_common;
+ int j, newlen = 0;
+
+ /* Sort the items. */
+ /* It is safe to sort this array, because the lowest common
+ denominator found in matches[0] will remain in place. */
+ for (i = 0; matches[i]; i++);
+ qsort (matches, i, sizeof (char *), compare_strings);
+
+ /* Remember the lowest common denimator for it may be unique. */
+ lowest_common = savestring (matches[0]);
+
+ for (i = 0; matches[i + 1]; i++)
+ {
+ if (strcmp (matches[i], matches[i + 1]) == 0)
+ {
+ free (matches[i]);
+ matches[i] = (char *)-1;
+ }
+ else
+ newlen++;
+ }
+
+ /* We have marked all the dead slots with (char *)-1.
+ Copy all the non-dead entries into a new array. */
+ {
+ char **temp_array =
+ (char **)malloc ((3 + newlen) * sizeof (char *));
+
+ for (i = 1, j = 1; matches[i]; i++)
+ if (matches[i] != (char *)-1)
+ temp_array[j++] = matches[i];
+ temp_array[j] = (char *)NULL;
+
+ if (matches[0] != (char *)-1)
+ free (matches[0]);
+ free (matches);
+
+ matches = temp_array;
+ }
+
+ /* Place the lowest common denominator back in [0]. */
+ matches[0] = lowest_common;
+
+ /* If there is one string left, and it is identical to the
+ lowest common denominator, then the LCD is the string to
+ insert. */
+ if (j == 2 && strcmp (matches[0], matches[1]) == 0)
+ {
+ free (matches[1]);
+ matches[1] = (char *)NULL;
+ }
+ }
+
+ switch (what_to_do)
+ {
+ case TAB:
+ rl_delete_text (start, rl_point);
+ rl_point = start;
+ rl_insert_text (matches[0]);
+
+ /* If there are more matches, ring the bell to indicate.
+ If this was the only match, and we are hacking files,
+ check the file to see if it was a directory. If so,
+ add a '/' to the name. If not, and we are at the end
+ of the line, then add a space. */
+ if (matches[1])
+ {
+ ding (); /* There are other matches remaining. */
+ }
+ else
+ {
+ char temp_string[2];
+
+ temp_string[0] = delimiter ? delimiter : ' ';
+ temp_string[1] = '\0';
+
+ if (rl_filename_completion_desired)
+ {
+ struct stat finfo;
+ char *tilde_expand ();
+ char *filename = tilde_expand (matches[0]);
+
+ if ((stat (filename, &finfo) == 0) &&
+ ((finfo.st_mode & S_IFMT) == S_IFDIR))
+ {
+ if (the_line[rl_point] != '/')
+ rl_insert_text ("/");
+ }
+ else
+ {
+ if (rl_point == rl_end)
+ rl_insert_text (temp_string);
+ }
+ free (filename);
+ }
+ else
+ {
+ if (rl_point == rl_end)
+ rl_insert_text (temp_string);
+ }
+ }
+ break;
+
+ case '*':
+ {
+ int i = 1;
+
+ rl_delete_text (start, rl_point);
+ rl_point = start;
+ rl_begin_undo_group ();
+ if (matches[1])
+ {
+ while (matches[i])
+ {
+ rl_insert_text (matches[i++]);
+ rl_insert_text (" ");
+ }
+ }
+ else
+ {
+ rl_insert_text (matches[0]);
+ rl_insert_text (" ");
+ }
+ rl_end_undo_group ();
+ }
+ break;
+
+
+ case '?':
+ {
+ int len, count, limit, max = 0;
+ int j, k, l;
+
+ /* Handle simple case first. What if there is only one answer? */
+ if (!matches[1])
+ {
+ char *temp;
+
+ if (rl_filename_completion_desired)
+ temp = rindex (matches[0], '/');
+ else
+ temp = (char *)NULL;
+
+ if (!temp)
+ temp = matches[0];
+ else
+ temp++;
+
+ crlf ();
+ fprintf (out_stream, "%s", temp);
+ crlf ();
+ goto restart;
+ }
+
+ /* There is more than one answer. Find out how many there are,
+ and find out what the maximum printed length of a single entry
+ is. */
+ for (i = 1; matches[i]; i++)
+ {
+ char *temp = (char *)NULL;
+
+ /* If we are hacking filenames, then only count the characters
+ after the last slash in the pathname. */
+ if (rl_filename_completion_desired)
+ temp = rindex (matches[i], '/');
+ else
+ temp = (char *)NULL;
+
+ if (!temp)
+ temp = matches[i];
+ else
+ temp++;
+
+ if (strlen (temp) > max)
+ max = strlen (temp);
+ }
+
+ len = i;
+
+ /* If there are many items, then ask the user if she
+ really wants to see them all. */
+ if (len >= rl_completion_query_items)
+ {
+ crlf ();
+ fprintf (out_stream,
+ "There are %d possibilities. Do you really", len);
+ crlf ();
+ fprintf (out_stream, "wish to see them all? (y or n)");
+ fflush (out_stream);
+ if (!get_y_or_n ())
+ {
+ crlf ();
+ goto restart;
+ }
+ }
+ /* How many items of MAX length can we fit in the screen window? */
+ max += 2;
+ limit = screenwidth / max;
+ if (limit != 1 && (limit * max == screenwidth))
+ limit--;
+
+ /* How many iterations of the printing loop? */
+ count = (len + (limit - 1)) / limit;
+
+ /* Watch out for special case. If LEN is less than LIMIT, then
+ just do the inner printing loop. */
+ if (len < limit) count = 1;
+
+ /* Sort the items if they are not already sorted. */
+ if (!rl_ignore_completion_duplicates)
+ {
+ qsort (matches, len, sizeof (char *), compare_strings);
+ }
+
+ /* Print the sorted items, up-and-down alphabetically, like
+ ls might. */
+ crlf ();
+
+ for (i = 1; i < count + 1; i++)
+ {
+ for (j = 0, l = i; j < limit; j++)
+ {
+ if (l > len || !matches[l])
+ {
+ break;
+ }
+ else
+ {
+ char *temp = (char *)NULL;
+
+ if (rl_filename_completion_desired)
+ temp = rindex (matches[l], '/');
+ else
+ temp = (char *)NULL;
+
+ if (!temp)
+ temp = matches[l];
+ else
+ temp++;
+
+ fprintf (out_stream, "%s", temp);
+ for (k = 0; k < max - strlen (temp); k++)
+ putc (' ', out_stream);
+ }
+ l += count;
+ }
+ crlf ();
+ }
+ restart:
+
+ rl_on_new_line ();
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ for (i = 0; matches[i]; i++)
+ free (matches[i]);
+ free (matches);
+ }
+}
+
+/* A completion function for usernames.
+ TEXT contains a partial username preceded by a random
+ character (usually `~'). */
+char *
+username_completion_function (text, state)
+ int state;
+ char *text;
+{
+ static char *username = (char *)NULL;
+ static struct passwd *entry;
+ static int namelen;
+
+ if (!state)
+ {
+ if (username)
+ free (username);
+ username = savestring (&text[1]);
+ namelen = strlen (username);
+ setpwent ();
+ }
+
+ while (entry = getpwent ())
+ {
+ if (strncmp (username, entry->pw_name, namelen) == 0)
+ break;
+ }
+
+ if (!entry)
+ {
+ endpwent ();
+ return ((char *)NULL);
+ }
+ else
+ {
+ char *value = (char *)xmalloc (2 + strlen (entry->pw_name));
+ *value = *text;
+ strcpy (value + 1, entry->pw_name);
+ rl_filename_completion_desired = 1;
+ return (value);
+ }
+}
+
+/* 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 *rl_tilde_expander = (Function *)NULL;
+
+/* Expand FILENAME if it begins with a tilde. This always returns
+ a new string. */
+char *
+tilde_expand (filename)
+ char *filename;
+{
+ char *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");
+
+ 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 (rl_tilde_expander)
+ {
+ char *expansion;
+
+ expansion = (char *)(*rl_tilde_expander) (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);
+ }
+ }
+ }
+ return (dirname);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Undo, and Undoing */
+/* */
+/* **************************************************************** */
+
+/* Non-zero tells rl_delete_text and rl_insert_text to not add to
+ the undo list. */
+int doing_an_undo = 0;
+
+/* The current undo list for THE_LINE. */
+UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
+
+/* Remember how to undo something. Concatenate some undos if that
+ seems right. */
+rl_add_undo (what, start, end, text)
+ enum undo_code what;
+ int start, end;
+ char *text;
+{
+ UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
+ temp->what = what;
+ temp->start = start;
+ temp->end = end;
+ temp->text = text;
+ temp->next = rl_undo_list;
+ rl_undo_list = temp;
+}
+
+/* Free the existing undo list. */
+free_undo_list ()
+{
+ while (rl_undo_list) {
+ UNDO_LIST *release = rl_undo_list;
+ rl_undo_list = rl_undo_list->next;
+
+ if (release->what == UNDO_DELETE)
+ free (release->text);
+
+ free (release);
+ }
+}
+
+/* Undo the next thing in the list. Return 0 if there
+ is nothing to undo, or non-zero if there was. */
+int
+rl_do_undo ()
+{
+ UNDO_LIST *release;
+ int waiting_for_begin = 0;
+
+undo_thing:
+ if (!rl_undo_list)
+ return (0);
+
+ doing_an_undo = 1;
+
+ switch (rl_undo_list->what) {
+
+ /* Undoing deletes means inserting some text. */
+ case UNDO_DELETE:
+ rl_point = rl_undo_list->start;
+ rl_insert_text (rl_undo_list->text);
+ free (rl_undo_list->text);
+ break;
+
+ /* Undoing inserts means deleting some text. */
+ case UNDO_INSERT:
+ rl_delete_text (rl_undo_list->start, rl_undo_list->end);
+ rl_point = rl_undo_list->start;
+ break;
+
+ /* Undoing an END means undoing everything 'til we get to
+ a BEGIN. */
+ case UNDO_END:
+ waiting_for_begin++;
+ break;
+
+ /* Undoing a BEGIN means that we are done with this group. */
+ case UNDO_BEGIN:
+ if (waiting_for_begin)
+ waiting_for_begin--;
+ else
+ abort ();
+ break;
+ }
+
+ doing_an_undo = 0;
+
+ release = rl_undo_list;
+ rl_undo_list = rl_undo_list->next;
+ free (release);
+
+ if (waiting_for_begin)
+ goto undo_thing;
+
+ return (1);
+}
+
+/* Begin a group. Subsequent undos are undone as an atomic operation. */
+rl_begin_undo_group ()
+{
+ rl_add_undo (UNDO_BEGIN, 0, 0, 0);
+}
+
+/* End an undo group started with rl_begin_undo_group (). */
+rl_end_undo_group ()
+{
+ rl_add_undo (UNDO_END, 0, 0, 0);
+}
+
+/* Save an undo entry for the text from START to END. */
+rl_modifying (start, end)
+ int start, end;
+{
+ if (start > end)
+ {
+ int t = start;
+ start = end;
+ end = t;
+ }
+
+ if (start != end)
+ {
+ char *temp = rl_copy (start, end);
+ rl_begin_undo_group ();
+ rl_add_undo (UNDO_DELETE, start, end, temp);
+ rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
+ rl_end_undo_group ();
+ }
+}
+
+/* Revert the current line to its previous state. */
+rl_revert_line ()
+{
+ if (!rl_undo_list) ding ();
+ else {
+ while (rl_undo_list)
+ rl_do_undo ();
+ }
+}
+
+/* Do some undoing of things that were done. */
+rl_undo_command (count)
+{
+ if (count < 0) return; /* Nothing to do. */
+
+ while (count)
+ {
+ if (rl_do_undo ())
+ {
+ count--;
+ }
+ else
+ {
+ ding ();
+ break;
+ }
+ }
+}
+
+/* **************************************************************** */
+/* */
+/* History Utilities */
+/* */
+/* **************************************************************** */
+
+/* We already have a history library, and that is what we use to control
+ the history features of readline. However, this is our local interface
+ to the history mechanism. */
+
+/* While we are editing the history, this is the saved
+ version of the original line. */
+HIST_ENTRY *saved_line_for_history = (HIST_ENTRY *)NULL;
+
+/* Set the history pointer back to the last entry in the history. */
+start_using_history ()
+{
+ using_history ();
+ if (saved_line_for_history)
+ free_history_entry (saved_line_for_history);
+
+ saved_line_for_history = (HIST_ENTRY *)NULL;
+}
+
+/* Free the contents (and containing structure) of a HIST_ENTRY. */
+free_history_entry (entry)
+ HIST_ENTRY *entry;
+{
+ if (!entry) return;
+ if (entry->line)
+ free (entry->line);
+ free (entry);
+}
+
+/* Perhaps put back the current line if it has changed. */
+maybe_replace_line ()
+{
+ HIST_ENTRY *temp = current_history ();
+
+ /* If the current line has changed, save the changes. */
+ if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list)) {
+ temp = replace_history_entry (where_history (), the_line, rl_undo_list);
+ free (temp->line);
+ free (temp);
+ }
+}
+
+/* Put back the saved_line_for_history if there is one. */
+maybe_unsave_line ()
+{
+ if (saved_line_for_history) {
+ strcpy (the_line, saved_line_for_history->line);
+ rl_undo_list = (UNDO_LIST *)saved_line_for_history->data;
+ free_history_entry (saved_line_for_history);
+ saved_line_for_history = (HIST_ENTRY *)NULL;
+ rl_end = rl_point = strlen (the_line);
+ } else {
+ ding ();
+ }
+}
+
+/* Save the current line in saved_line_for_history. */
+maybe_save_line ()
+{
+ if (!saved_line_for_history) {
+ saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+ saved_line_for_history->line = savestring (the_line);
+ saved_line_for_history->data = (char *)rl_undo_list;
+ }
+}
+
+
+
+/* **************************************************************** */
+/* */
+/* History Commands */
+/* */
+/* **************************************************************** */
+
+/* Meta-< goes to the start of the history. */
+rl_beginning_of_history ()
+{
+ rl_get_previous_history (1 + where_history ());
+}
+
+/* Meta-> goes to the end of the history. (The current line). */
+rl_end_of_history ()
+{
+ maybe_replace_line ();
+ using_history ();
+ maybe_unsave_line ();
+}
+
+/* Move down to the next history line. */
+rl_get_next_history (count)
+ int count;
+{
+ HIST_ENTRY *temp = (HIST_ENTRY *)NULL;
+
+ if (count < 0)
+ {
+ rl_get_previous_history (-count);
+ return;
+ }
+
+ if (!count)
+ return;
+
+ maybe_replace_line ();
+
+ while (count)
+ {
+ temp = next_history ();
+ if (!temp)
+ break;
+ --count;
+ }
+
+ if (!temp)
+ maybe_unsave_line ();
+ else
+ {
+ strcpy (the_line, temp->line);
+ rl_undo_list = (UNDO_LIST *)temp->data;
+ rl_end = rl_point = strlen (the_line);
+ }
+}
+
+/* Get the previous item out of our interactive history, making it the current
+ line. If there is no previous history, just ding. */
+rl_get_previous_history (count)
+ int count;
+{
+ HIST_ENTRY *old_temp = (HIST_ENTRY *)NULL;
+ HIST_ENTRY *temp = (HIST_ENTRY *)NULL;
+
+ if (count < 0)
+ {
+ rl_get_next_history (-count);
+ return;
+ }
+
+ if (!count)
+ return;
+
+ /* If we don't have a line saved, then save this one. */
+ maybe_save_line ();
+
+ /* If the current line has changed, save the changes. */
+ maybe_replace_line ();
+
+ while (count)
+ {
+ temp = previous_history ();
+ if (!temp)
+ break;
+ else
+ old_temp = temp;
+ --count;
+ }
+
+ /* If there was a large argument, and we moved back to the start of the
+ history, that is not an error. So use the last value found. */
+ if (!temp && old_temp)
+ temp = old_temp;
+
+ if (!temp)
+ ding ();
+ else
+ {
+ strcpy (the_line, temp->line);
+ rl_undo_list = (UNDO_LIST *)temp->data;
+ rl_end = rl_point = strlen (the_line);
+#ifdef VI_MODE
+ if (rl_editing_mode == vi_mode)
+ rl_point = 0;
+#endif /* VI_MODE */
+ }
+}
+
+/* There is a command in ksh which yanks into this line, the last word
+ of the previous line. Here it is. We left it on M-. */
+rl_yank_previous_last_arg (ignore)
+ int ignore;
+{
+}
+
+
+
+/* **************************************************************** */
+/* */
+/* I-Search and Searching */
+/* */
+/* **************************************************************** */
+
+/* Search backwards through the history looking for a string which is typed
+ interactively. Start with the current line. */
+rl_reverse_search_history (sign, key)
+ int sign;
+ int key;
+{
+ rl_search_history (-sign, key);
+}
+
+/* Search forwards through the history looking for a string which is typed
+ interactively. Start with the current line. */
+rl_forward_search_history (sign, key)
+ int sign;
+ int key;
+{
+ rl_search_history (sign, key);
+}
+
+/* Display the current state of the search in the echo-area.
+ SEARCH_STRING contains the string that is being searched for,
+ DIRECTION is zero for forward, or 1 for reverse,
+ WHERE is the history list number of the current line. If it is
+ -1, then this line is the starting one. */
+rl_display_search (search_string, reverse_p, where)
+ char *search_string;
+ int reverse_p, where;
+{
+ char *message = (char *)NULL;
+
+ message =
+ (char *)alloca (1 + (search_string ? strlen (search_string) : 0) + 30);
+
+ *message = '\0';
+
+#ifdef NEVER
+ if (where != -1)
+ sprintf (message, "[%d]", where + history_base);
+#endif
+
+ strcat (message, "(");
+
+ if (reverse_p)
+ strcat (message, "reverse-");
+
+ strcat (message, "i-search)`");
+
+ if (search_string)
+ strcat (message, search_string);
+
+ strcat (message, "': ");
+ rl_message (message, 0, 0);
+ rl_redisplay ();
+}
+
+/* Search through the history looking for an interactively typed string.
+ This is analogous to i-search. We start the search in the current line.
+ DIRECTION is which direction to search; > 0 means forward, < 0 means
+ backwards. */
+rl_search_history (direction, invoking_key)
+ int direction;
+ int invoking_key;
+{
+ /* The string that the user types in to search for. */
+ char *search_string = (char *)alloca (128);
+
+ /* The current length of SEARCH_STRING. */
+ int search_string_index;
+
+ /* The list of lines to search through. */
+ char **lines;
+
+ /* The length of LINES. */
+ int hlen;
+
+ /* Where we get LINES from. */
+ HIST_ENTRY **hlist = history_list ();
+
+ int orig_point = rl_point;
+ int orig_line = where_history ();
+ int last_found_line = orig_line;
+ int c, done = 0;
+ register int i = 0;
+
+
+ /* The line currently being searched. */
+ char *sline;
+
+ /* Offset in that line. */
+ int index;
+
+ /* Non-zero if we are doing a reverse search. */
+ int reverse = (direction < 0);
+
+ /* Create an arrary of pointers to the lines that we want to search. */
+
+ maybe_replace_line ();
+ if (hlist)
+ for (i = 0; hlist[i]; i++);
+
+ /* Allocate space for this many lines, +1 for the current input line,
+ and remember those lines. */
+ lines = (char **)alloca ((1 + (hlen = i)) * sizeof (char *));
+ for (i = 0; i < hlen; i++)
+ lines[i] = hlist[i]->line;
+
+ if (saved_line_for_history)
+ lines[i] = saved_line_for_history->line;
+ else
+ {
+ /* So I have to type it in this way instead. */
+ lines[i] = (char *)alloca (1 + strlen (the_line));
+ strcpy (lines[i], &the_line[0]);
+ }
+
+ hlen++;
+
+ /* The line where we start the search. */
+ i = orig_line;
+
+ /* Initialize search parameters. */
+ *search_string = '\0';
+ search_string_index = 0;
+
+ rl_display_search (search_string, reverse, -1);
+
+ sline = the_line;
+ index = rl_point;
+
+ while (!done)
+ {
+ c = rl_read_key (in_stream);
+
+ /* Hack C to Do What I Mean. */
+ {
+ Function *f = (Function *)NULL;
+
+ if (keymap[c].type == ISFUNC)
+ f = keymap[c].function;
+
+ if (f == rl_reverse_search_history)
+ c = reverse ? -1 : -2;
+ else if (f == rl_forward_search_history)
+ c = !reverse ? -1 : -2;
+ }
+
+ switch (c)
+ {
+ case ESC:
+ done = 1;
+ continue;
+
+ /* case invoking_key: */
+ case -1:
+ goto search_again;
+
+ /* switch directions */
+ case -2:
+ direction = -direction;
+ reverse = (direction < 0);
+
+ goto do_search;
+
+ case CTRL ('G'):
+ strcpy (the_line, lines[orig_line]);
+ rl_point = orig_point;
+ rl_end = strlen (the_line);
+ rl_clear_message ();
+ return;
+
+ default:
+ if (c < 32 || c > 126)
+ {
+ rl_execute_next (c);
+ done = 1;
+ continue;
+ }
+ else
+ {
+ search_string[search_string_index++] = c;
+ search_string[search_string_index] = '\0';
+ goto do_search;
+
+ search_again:
+
+ if (!search_string_index)
+ continue;
+ else
+ {
+ if (reverse)
+ --index;
+ else
+ if (index != strlen (sline))
+ ++index;
+ else
+ ding ();
+ }
+ do_search:
+
+ while (1)
+ {
+ if (reverse)
+ {
+ while (index >= 0)
+ if (strncmp
+ (search_string,
+ sline + index,
+ search_string_index) == 0)
+ goto string_found;
+ else
+ index--;
+ }
+ else
+ {
+ register int limit =
+ (strlen (sline) - search_string_index) + 1;
+
+ while (index < limit)
+ {
+ if (strncmp (search_string,
+ sline + index,
+ search_string_index) == 0)
+ goto string_found;
+ index++;
+ }
+ }
+
+ next_line:
+ i += direction;
+
+ /* At limit for direction? */
+ if ((reverse && i < 0) ||
+ (!reverse && i == hlen))
+ goto search_failed;
+
+ sline = lines[i];
+ if (reverse)
+ index = strlen (sline);
+ else
+ index = 0;
+
+ /* If the search string is longer than the current
+ line, no match. */
+ if (search_string_index > strlen (sline))
+ goto next_line;
+
+ /* Start actually searching. */
+ if (reverse)
+ index -= search_string_index;
+ }
+
+ search_failed:
+ /* We cannot find the search string. Ding the bell. */
+ ding ();
+ i = last_found_line;
+ break;
+
+ string_found:
+ /* We have found the search string. Just display it. But don't
+ actually move there in the history list until the user accepts
+ the location. */
+ strcpy (the_line, lines[i]);
+ rl_point = index;
+ rl_end = strlen (the_line);
+ last_found_line = i;
+ rl_display_search (search_string, reverse,
+ (i == orig_line) ? -1 : i);
+ }
+ }
+ continue;
+ }
+ /* The user has won. They found the string that they wanted. Now all
+ we have to do is place them there. */
+ {
+ int now = last_found_line;
+
+ /* First put back the original state. */
+ strcpy (the_line, lines[orig_line]);
+
+ if (now < orig_line)
+ rl_get_previous_history (orig_line - now);
+ else
+ rl_get_next_history (now - orig_line);
+
+ rl_point = index;
+ rl_clear_message ();
+ }
+}
+
+/* Make C be the next command to be executed. */
+rl_execute_next (c)
+ int c;
+{
+ rl_pending_input = c;
+}
+
+/* **************************************************************** */
+/* */
+/* Killing Mechanism */
+/* */
+/* **************************************************************** */
+
+/* What we assume for a max number of kills. */
+#define DEFAULT_MAX_KILLS 10
+
+/* The real variable to look at to find out when to flush kills. */
+int rl_max_kills = DEFAULT_MAX_KILLS;
+
+/* Where to store killed text. */
+char **rl_kill_ring = (char **)NULL;
+
+/* Where we are in the kill ring. */
+int rl_kill_index = 0;
+
+/* How many slots we have in the kill ring. */
+int rl_kill_ring_length = 0;
+
+/* How to say that you only want to save a certain amount
+ of kill material. */
+rl_set_retained_kills (num)
+ int num;
+{}
+
+/* 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 text is appended, otherwise prepended. If the
+ last command was not a kill command, then a new slot is made for
+ this kill. */
+rl_kill_text (from, to)
+ int from, to;
+{
+ int slot;
+ char *text = rl_copy (from, to);
+
+ /* Is there anything to kill? */
+ if (from == to) {
+ free (text);
+ last_command_was_kill++;
+ return;
+ }
+
+ /* Delete the copied text from the line. */
+ rl_delete_text (from, to);
+
+ /* First, find the slot to work with. */
+ if (!last_command_was_kill) {
+
+ /* Get a new slot. */
+ if (!rl_kill_ring) {
+
+ /* If we don't have any defined, then make one. */
+ rl_kill_ring =
+ (char **)xmalloc (((rl_kill_ring_length = 1) + 1) * sizeof (char *));
+ slot = 1;
+
+ } else {
+
+ /* We have to add a new slot on the end, unless we have exceeded
+ the max limit for remembering kills. */
+ slot = rl_kill_ring_length;
+ if (slot == rl_max_kills) {
+ register int i;
+ free (rl_kill_ring[0]);
+ for (i = 0; i < slot; i++)
+ rl_kill_ring[i] = rl_kill_ring[i + 1];
+ } else {
+ rl_kill_ring =
+ (char **)xrealloc (rl_kill_ring,
+ ((slot = (rl_kill_ring_length += 1)) + 1)
+ * sizeof (char *));
+ }
+ }
+ slot--;
+ } else {
+ slot = rl_kill_ring_length - 1;
+ }
+
+ /* If the last command was a kill, prepend or append. */
+ if (last_command_was_kill) {
+ char *old = rl_kill_ring[slot];
+ char *new = (char *)xmalloc (1 + strlen (old) + strlen (text));
+
+ if (from < to) {
+ strcpy (new, old);
+ strcat (new, text);
+ } else {
+ strcpy (new, text);
+ strcat (new, old);
+ }
+ free (old);
+ free (text);
+ rl_kill_ring[slot] = new;
+ } else {
+ rl_kill_ring[slot] = text;
+ }
+ rl_kill_index = slot;
+ last_command_was_kill++;
+}
+
+/* Now REMEMBER! In order to do prepending or appending correctly, kill
+ commands always make rl_point's original position be the FROM argument,
+ and rl_point's extent be the TO argument. */
+
+
+/* **************************************************************** */
+/* */
+/* Killing Commands */
+/* */
+/* **************************************************************** */
+
+/* Delete the word at point, saving the text in the kill ring. */
+rl_kill_word (count)
+ int count;
+{
+ int orig_point = rl_point;
+
+ if (count < 0)
+ rl_backward_kill_word (-count);
+ else
+ {
+ rl_forward_word (count);
+
+ if (rl_point != orig_point)
+ rl_kill_text (orig_point, rl_point);
+
+ rl_point = orig_point;
+ }
+}
+
+/* Rubout the word before point, placing it on the kill ring. */
+rl_backward_kill_word (count)
+ int count;
+{
+ int orig_point = rl_point;
+
+ if (count < 0)
+ rl_kill_word (-count);
+ else
+ {
+ rl_backward_word (count);
+
+ if (rl_point != orig_point)
+ rl_kill_text (orig_point, rl_point);
+ }
+}
+
+/* Kill from here to the end of the line. If DIRECTION is negative, kill
+ back to the line start instead. */
+rl_kill_line (direction)
+ int direction;
+{
+ int orig_point = rl_point;
+
+ if (direction < 0)
+ rl_backward_kill_line (1);
+ else
+ {
+ rl_end_of_line ();
+ if (orig_point != rl_point)
+ rl_kill_text (orig_point, rl_point);
+ rl_point = orig_point;
+ }
+}
+
+/* Kill backwards to the start of the line. If DIRECTION is negative, kill
+ forwards to the line end instead. */
+rl_backward_kill_line (direction)
+ int direction;
+{
+ int orig_point = rl_point;
+
+ if (direction < 0)
+ rl_kill_line (1);
+ else
+ {
+ if (!rl_point)
+ ding ();
+ else
+ {
+ rl_beg_of_line ();
+ rl_kill_text (orig_point, rl_point);
+ }
+ }
+}
+
+/* Yank back the last killed text. This ignores arguments. */
+rl_yank ()
+{
+ if (!rl_kill_ring) rl_abort ();
+ rl_insert_text (rl_kill_ring[rl_kill_index]);
+}
+
+/* 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. */
+rl_yank_pop ()
+{
+ int l;
+
+ if (((rl_last_func != rl_yank_pop) && (rl_last_func != rl_yank)) ||
+ !rl_kill_ring)
+ {
+ rl_abort ();
+ }
+
+ l = strlen (rl_kill_ring[rl_kill_index]);
+ if (((rl_point - l) >= 0) &&
+ (strncmp (the_line + (rl_point - l),
+ rl_kill_ring[rl_kill_index], l) == 0))
+ {
+ rl_delete_text ((rl_point - l), rl_point);
+ rl_point -= l;
+ rl_kill_index--;
+ if (rl_kill_index < 0)
+ rl_kill_index = rl_kill_ring_length - 1;
+ rl_yank ();
+ }
+ else
+ rl_abort ();
+
+}
+
+/* Yank the COUNTth argument from the previous history line. */
+rl_yank_nth_arg (count, ignore)
+ int count;
+{
+ register HIST_ENTRY *entry = previous_history ();
+ char *arg;
+
+ if (entry)
+ next_history ();
+ else
+ {
+ ding ();
+ return;
+ }
+
+ arg = history_arg_extract (count, count, entry->line);
+ if (!arg || !*arg)
+ {
+ ding ();
+ return;
+ }
+
+ rl_begin_undo_group ();
+ if (rl_point && the_line[rl_point - 1] != ' ')
+ rl_insert_text (" ");
+ rl_insert_text (arg);
+ free (arg);
+ rl_end_undo_group ();
+}
+
+/* Vi Mode. */
+#ifdef VI_MODE
+#include "vi_mode.c"
+#endif /* VI_MODE */
+
+/* How to toggle back and forth between editing modes. */
+rl_vi_editing_mode ()
+{
+#ifdef VI_MODE
+ rl_editing_mode = vi_mode;
+ rl_vi_insertion_mode ();
+#endif /* VI_MODE */
+}
+
+rl_emacs_editing_mode ()
+{
+ rl_editing_mode = emacs_mode;
+ keymap = emacs_standard_keymap;
+}
+
+
+/* **************************************************************** */
+/* */
+/* Completion */
+/* */
+/* **************************************************************** */
+
+/* Non-zero means that case is not significant in completion. */
+int completion_case_fold = 0;
+
+/* Return an array of (char *) which is a list of completions for TEXT.
+ If there are no completions, return a NULL pointer.
+ The first entry in the returned array is the substitution for TEXT.
+ The remaining entries are the possible completions.
+ The array is terminated with a NULL pointer.
+
+ ENTRY_FUNCTION is a function of two args, and returns a (char *).
+ The first argument is TEXT.
+ The second is a state argument; it should be zero on the first call, and
+ non-zero on subsequent calls. It returns a NULL pointer to the caller
+ when there are no more matches.
+ */
+char **
+completion_matches (text, entry_function)
+ char *text;
+ char *(*entry_function) ();
+{
+ /* Number of slots in match_list. */
+ int match_list_size;
+
+ /* The list of matches. */
+ char **match_list =
+ (char **)xmalloc (((match_list_size = 10) + 1) * sizeof (char *));
+
+ /* Number of matches actually found. */
+ int matches = 0;
+
+ /* Temporary string binder. */
+ char *string;
+
+ match_list[1] = (char *)NULL;
+
+ while (string = (*entry_function) (text, matches))
+ {
+ if (matches + 1 == match_list_size)
+ match_list =
+ (char **)xrealloc (match_list,
+ ((match_list_size += 10) + 1) * sizeof (char *));
+
+ match_list[++matches] = string;
+ match_list[matches + 1] = (char *)NULL;
+ }
+
+ /* If there were any matches, then look through them finding out the
+ lowest common denominator. That then becomes match_list[0]. */
+ if (matches)
+ {
+ register int i = 1;
+ int low = 100000; /* Count of max-matched characters. */
+
+ /* If only one match, just use that. */
+ if (matches == 1)
+ {
+ match_list[0] = match_list[1];
+ match_list[1] = (char *)NULL;
+ }
+ else
+ {
+ /* Otherwise, compare each member of the list with
+ the next, finding out where they stop matching. */
+
+ while (i < matches)
+ {
+ register int c1, c2, si;
+
+ if (completion_case_fold)
+ {
+ for (si = 0;
+ (c1 = to_lower(match_list[i][si])) &&
+ (c2 = to_lower(match_list[i + 1][si]));
+ si++)
+ if (c1 != c2) break;
+ }
+ else
+ {
+ for (si = 0;
+ (c1 = match_list[i][si]) &&
+ (c2 = match_list[i + 1][si]);
+ si++)
+ if (c1 != c2) break;
+ }
+
+ if (low > si) low = si;
+ i++;
+ }
+ match_list[0] = (char *)xmalloc (low + 1);
+ strncpy (match_list[0], match_list[1], low);
+ match_list[0][low] = '\0';
+ }
+ }
+ else /* There were no matches. */
+ {
+ free (match_list);
+ match_list = (char **)NULL;
+ }
+ return (match_list);
+}
+
+/* Okay, now we write the entry_function for filename completion. In the
+ general case. Note that completion in the shell is a little different
+ because of all the pathnames that must be followed when looking up the
+ completion for a command. */
+char *
+filename_completion_function (text, state)
+ int state;
+ char *text;
+{
+ static DIR *directory;
+ static char *filename = (char *)NULL;
+ static char *dirname = (char *)NULL;
+ static char *users_dirname = (char *)NULL;
+ static int filename_len;
+
+ struct direct *entry = (struct direct *)NULL;
+
+ /* If we don't have any state, then do some initialization. */
+ if (!state)
+ {
+ char *temp;
+
+ if (dirname) free (dirname);
+ if (filename) free (filename);
+ if (users_dirname) free (users_dirname);
+
+ filename = savestring (text);
+ if (!*text) text = ".";
+ dirname = savestring (text);
+
+ temp = rindex (dirname, '/');
+
+ if (temp)
+ {
+ strcpy (filename, ++temp);
+ *temp = '\0';
+ }
+ else
+ strcpy (dirname, ".");
+
+ /* We aren't done yet. We also support the "~user" syntax. */
+
+ /* Save the version of the directory that the user typed. */
+ users_dirname = savestring (dirname);
+ {
+ char *tilde_expand (), *temp_dirname = tilde_expand (dirname);
+ free (dirname);
+ dirname = temp_dirname;
+#ifdef SHELL
+ {
+ extern int follow_symbolic_links;
+ char *make_absolute ();
+
+ if (follow_symbolic_links && (strcmp (dirname, ".") != 0))
+ {
+ temp_dirname = make_absolute (dirname, get_working_directory (""));
+
+ if (temp_dirname)
+ {
+ free (dirname);
+ dirname = temp_dirname;
+ }
+ }
+ }
+#endif /* SHELL */
+ }
+ directory = opendir (dirname);
+ filename_len = strlen (filename);
+
+ rl_filename_completion_desired = 1;
+ }
+
+ /* At this point we should entertain the possibility of hacking wildcarded
+ filenames, like /usr/man*\/te<TAB>. If the directory name contains
+ globbing characters, then build an array of directories to glob on, and
+ glob on the first one. */
+
+ /* Now that we have some state, we can read the directory. */
+
+ while (directory && (entry = readdir (directory)))
+ {
+ /* Special case for no filename.
+ All entries except "." and ".." match. */
+ if (!filename_len)
+ {
+ if ((strcmp (entry->d_name, ".") != 0) &&
+ (strcmp (entry->d_name, "..") != 0))
+ break;
+ }
+ else
+ {
+ /* Otherwise, if these match upto the length of filename, then
+ it is a match. */
+#ifdef TMB_SYSV
+ if ((strlen (entry->d_name) >= filename_len) &&
+ (strncmp (filename, entry->d_name, filename_len) == 0))
+#else
+ if ((entry->d_namlen >= filename_len) &&
+ (strncmp (filename, entry->d_name, filename_len) == 0))
+#endif /* TMB_SYSV */
+ {
+ break;
+ }
+ }
+ }
+
+ if (!entry)
+ {
+ if (directory)
+ {
+ closedir (directory);
+ directory = (DIR *)NULL;
+ }
+ return (char *)NULL;
+ }
+ else
+ {
+ char *temp;
+
+ if (dirname && (strcmp (dirname, ".") != 0))
+ {
+#ifdef TMB_SYSV
+ temp = (char *)xmalloc (1 + strlen (users_dirname)
+ + strlen (entry->d_name));
+#else
+ temp = (char *)xmalloc (1 + strlen (users_dirname)
+ + entry->d_namlen);
+#endif /* TMB_SYSV */
+ strcpy (temp, users_dirname);
+ strcat (temp, entry->d_name);
+ }
+ else
+ {
+ temp = (savestring (entry->d_name));
+ }
+ return (temp);
+ }
+}
+
+
+/* **************************************************************** */
+/* */
+/* Binding keys */
+/* */
+/* **************************************************************** */
+
+/* rl_add_defun (char *name, Function *function, int key)
+ Add NAME to the list of named functions. Make FUNCTION
+ be the function that gets called.
+ If KEY is not -1, then bind it. */
+rl_add_defun (name, function, key)
+ char *name;
+ Function *function;
+ int key;
+{
+ if (key != -1)
+ rl_bind_key (key, function);
+ rl_add_funmap_entry (name, function);
+}
+
+/* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */
+int
+rl_bind_key (key, function)
+ int key;
+ Function *function;
+{
+ if (key < 0)
+ return (key);
+
+ if (key > 127 && key < 256)
+ {
+ if (keymap[ESC].type == ISKMAP)
+ {
+ Keymap escmap = (Keymap)keymap[ESC].function;
+
+ key -= 128;
+ escmap[key].type = ISFUNC;
+ escmap[key].function = function;
+ return (0);
+ }
+ return (key);
+ }
+
+ keymap[key].type = ISFUNC;
+ keymap[key].function = function;
+ return (0);
+}
+
+/* Bind KEY to FUNCTION in MAP. Returns non-zero in case of invalid
+ KEY. */
+int
+rl_bind_key_in_map (key, function, map)
+ int key;
+ Function *function;
+ Keymap map;
+{
+ int result;
+ Keymap oldmap = keymap;
+
+ keymap = map;
+ result = rl_bind_key (key, function);
+ keymap = oldmap;
+ return (result);
+}
+
+/* Make KEY do nothing in the currently selected keymap.
+ Returns non-zero in case of error. */
+int
+rl_unbind_key (key)
+ int key;
+{
+ return (rl_bind_key (key, (Function *)NULL));
+}
+
+/* Make KEY do nothing in MAP.
+ Returns non-zero in case of error. */
+int
+rl_unbind_key_in_map (key, map)
+ int key;
+ Keymap map;
+{
+ return (rl_bind_key_in_map (key, (Function *)NULL, map));
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+ FUNCTION. This makes new keymaps as necessary. The initial
+ place to do bindings is in MAP. */
+rl_set_key (keyseq, function, map)
+ char *keyseq;
+ Function *function;
+ Keymap map;
+{
+ rl_generic_bind (ISFUNC, keyseq, function, map);
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+ the string of characters MACRO. This makes new keymaps as
+ necessary. The initial place to do bindings is in MAP. */
+rl_macro_bind (keyseq, macro, map)
+ char *keyseq, *macro;
+ Keymap map;
+{
+ char *macro_keys = (char *)xmalloc (2 * (strlen (macro)));
+ int macro_keys_len;
+
+ if (rl_translate_keyseq (macro, macro_keys, &macro_keys_len))
+ {
+ free (macro_keys);
+ return;
+ }
+ rl_generic_bind (ISMACR, keyseq, macro_keys, map);
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+ the arbitrary pointer DATA. TYPE says what kind of data is
+ pointed to by DATA, right now this can be a function (ISFUNC),
+ a macro (ISMACR), or a keymap (ISKMAP). This makes new keymaps
+ as necessary. The initial place to do bindings is in MAP. */
+rl_generic_bind (type, keyseq, data, map)
+ int type;
+ char *keyseq, *data;
+ Keymap map;
+{
+ char *keys;
+ int keys_len;
+ register int i;
+ int start;
+
+ /* If no keys to bind to, exit right away. */
+ if (!keyseq || !*keyseq)
+ {
+ if (type == ISMACR)
+ free (data);
+ return;
+ }
+
+ keys = (char *)alloca (1 + (2 * strlen (keyseq)));
+
+ /* Translate the ASCII representation of KEYSEQ into an array
+ of characters. Stuff the characters into ARRAY, and the
+ length of ARRAY into LENGTH. */
+ if (rl_translate_keyseq (keyseq, keys, &keys_len))
+ return;
+
+ /* Handle mapping of the ESC Key in vi mode */
+ start = 0;
+#ifdef VI_MODE
+ if ((rl_editing_mode == vi_mode) && (keys[0] == ESC))
+ {
+ start++;
+ map = vi_movement_keymap;
+ if(keys[1] == ESC)
+ {
+ extern KEYMAP_ENTRY_ARRAY vi_escape_keymap;
+
+ start++;
+ map = vi_escape_keymap;
+ }
+ }
+#endif
+
+ /* Bind keys, making new keymaps as necessary. */
+ for (i = start; i < keys_len; i++)
+ {
+ if (i + 1 < keys_len)
+ {
+ if (map[keys[i]].type != ISKMAP)
+ {
+ if (map[i].type == ISMACR)
+ free ((char *)map[i].function);
+
+ map[keys[i]].type = ISKMAP;
+ map[keys[i]].function = (Function *)rl_make_bare_keymap ();
+ }
+ map = (Keymap)map[keys[i]].function;
+ }
+ else
+ {
+ if (map[keys[i]].type == ISMACR)
+ free ((char *)map[keys[i]].function);
+
+ map[keys[i]].function = (Function *)data;
+ map[keys[i]].type = type;
+ }
+ }
+}
+
+/* Translate the ASCII representation of SEQ, stuffing the
+ values into ARRAY, an array of characters. LEN gets the
+ final length of ARRAY. Return non-zero if there was an
+ error parsing SEQ. */
+rl_translate_keyseq (seq, array, len)
+ char *seq, *array;
+ int *len;
+{
+ register int i, c, l = 0;
+
+ for (i = 0; c = seq[i]; i++)
+ {
+ if (c == '\\')
+ {
+ c = seq[++i];
+
+ if (!c)
+ break;
+
+ if (((c == 'C' || c == 'M') && seq[i + 1] == '-') ||
+ (c == 'e'))
+ {
+ /* Handle special case of backwards define. */
+ if (strncmp (&seq[i], "C-\\M-", 5) == 0)
+ {
+ array[l++] = ESC;
+ i += 5;
+ array[l++] = CTRL (to_upper (seq[i]));
+ if (!seq[i])
+ i--;
+ continue;
+ }
+
+ switch (c)
+ {
+ case 'M':
+ i++;
+ array[l++] = ESC;
+ break;
+
+ case 'C':
+ i += 2;
+ array[l++] = CTRL (to_upper (seq[i]));
+ break;
+
+ case 'e':
+ array[l++] = ESC;
+ }
+
+ continue;
+ }
+ }
+ array[l++] = c;
+ }
+
+ array[l] = '\0';
+ *len = l;
+ return (0);
+}
+
+/* Return a pointer to the function that STRING represents.
+ If STRING doesn't have a matching function, then a NULL pointer
+ is returned. */
+Function *
+rl_named_function (string)
+ char *string;
+{
+ register int i;
+ static int stricmp ();
+
+ for (i = 0; funmap[i]; i++)
+ if (stricmp (funmap[i]->name, string) == 0)
+ return (funmap[i]->function);
+ return ((Function *)NULL);
+}
+
+/* The last key bindings file read. */
+static char *last_readline_init_file = "~/.inputrc";
+
+/* Re-read the current keybindings file. */
+rl_re_read_init_file (count, ignore)
+ int count, ignore;
+{
+ rl_read_init_file (last_readline_init_file);
+}
+
+/* Do key bindings from a file. If FILENAME is NULL it defaults
+ to `~/.inputrc'. If the file existed and could be opened and
+ read, 0 is returned, otherwise errno is returned. */
+int
+rl_read_init_file (filename)
+ char *filename;
+{
+ int line_size, line_index;
+ char *line = (char *)xmalloc (line_size = 100);
+ char *openname;
+ FILE *file;
+
+ int c;
+
+ /* Default the filename. */
+ if (!filename)
+ filename = "~/.inputrc";
+
+ openname = tilde_expand (filename);
+
+ /* Open the file. */
+ file = fopen (openname, "r");
+ free (openname);
+
+ if (!file)
+ return (errno);
+
+ last_readline_init_file = filename;
+
+ /* Loop reading lines from the file. Lines that start with `#' are
+ comments, all other lines are commands for readline initialization. */
+ while ((c = getc(file)) != EOF)
+ {
+ /* If comment, flush to EOL. */
+ if (c == '#')
+ {
+ while ((c = getc(file)) != EOF && c != '\n');
+ if (c == EOF)
+ goto function_exit;
+ continue;
+ }
+
+ /* Otherwise, this is the start of a line. Read the
+ line from the file. */
+ line_index = 0;
+ while (c != EOF && c != '\n')
+ {
+ line[line_index++] = c;
+ if (line_index == line_size)
+ line = (char *)xrealloc (line, line_size += 100);
+ c = getc (file);
+ }
+ line[line_index] = '\0';
+
+ /* Parse the line. */
+ rl_parse_and_bind (line);
+ }
+
+function_exit:
+
+ free (line);
+ /* Close up the file and exit. */
+ fclose (file);
+ return (0);
+}
+
+
+/* **************************************************************** */
+/* */
+/* Parser Directives */
+/* */
+/* **************************************************************** */
+
+/* Conditionals. */
+
+/* Calling programs set this to have their argv[0]. */
+char *rl_readline_name = "other";
+
+/* Stack of previous values of parsing_conditionalized_out. */
+static unsigned char *if_stack = (unsigned char *)NULL;
+static int if_stack_depth = 0;
+static int if_stack_size = 0;
+
+/* Push parsing_conditionalized_out, and set parser state based on ARGS. */
+parser_if (args)
+ char *args;
+{
+ register int i;
+ static int stricmp ();
+
+ /* Push parser state. */
+ if (if_stack_depth + 1 >= if_stack_size)
+ {
+ if (!if_stack)
+ if_stack = (unsigned char *)xmalloc (if_stack_size = 20);
+ else
+ if_stack = (unsigned char *)xrealloc (if_stack, if_stack_size += 20);
+ }
+ if_stack[if_stack_depth++] = parsing_conditionalized_out;
+
+ /* We only check to see if the first word in ARGS is the same as the
+ value stored in rl_readline_name. */
+
+ /* Isolate first argument. */
+ for (i = 0; args[i] && !whitespace (args[i]); i++);
+
+ if (args[i])
+ args[i++] = '\0';
+
+ if (stricmp (args, rl_readline_name) == 0)
+ parsing_conditionalized_out = 0;
+ else
+ parsing_conditionalized_out = 1;
+}
+
+/* Invert the current parser state if there is anything on the stack. */
+parser_else (args)
+ char *args;
+{
+ if (if_stack_depth)
+ parsing_conditionalized_out = !parsing_conditionalized_out;
+ else
+ {
+ /* *** What, no error message? *** */
+ }
+}
+
+/* Terminate a conditional, popping the value of
+ parsing_conditionalized_out from the stack. */
+parser_endif (args)
+ char *args;
+{
+ if (if_stack_depth)
+ parsing_conditionalized_out = if_stack[--if_stack_depth];
+ else
+ {
+ /* *** What, no error message? *** */
+ }
+}
+
+/* Associate textual names with actual functions. */
+static struct {
+ char *name;
+ Function *function;
+} parser_directives [] = {
+ { "if", parser_if },
+ { "endif", parser_endif },
+ { "else", parser_else },
+ { (char *)0x0, (Function *)0x0 }
+};
+
+/* Handle a parser directive. STATEMENT is the line of the directive
+ without any leading `$'. */
+static int
+handle_parser_directive (statement)
+ char *statement;
+{
+ register int i;
+ char *directive, *args;
+ static int stricmp ();
+
+ /* Isolate the actual directive. */
+
+ /* Skip whitespace. */
+ for (i = 0; whitespace (statement[i]); i++);
+
+ directive = &statement[i];
+
+ for (; statement[i] && !whitespace (statement[i]); i++);
+
+ if (statement[i])
+ statement[i++] = '\0';
+
+ for (; statement[i] && whitespace (statement[i]); i++);
+
+ args = &statement[i];
+
+ /* Lookup the command, and act on it. */
+ for (i = 0; parser_directives[i].name; i++)
+ if (stricmp (directive, parser_directives[i].name) == 0)
+ {
+ (*parser_directives[i].function) (args);
+ return (0);
+ }
+
+ /* *** Should an error message be output? */
+ return (1);
+}
+
+/* Read the binding command from STRING and perform it.
+ A key binding command looks like: Keyname: function-name\0,
+ a variable binding command looks like: set variable value.
+ A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */
+rl_parse_and_bind (string)
+ char *string;
+{
+ extern char *possible_control_prefixes[], *possible_meta_prefixes[];
+ char *funname, *kname;
+ static int substring_member_of_array (), stricmp ();
+ register int c;
+ int key, i;
+
+ if (!string || !*string || *string == '#')
+ return;
+
+ /* If this is a parser directive, act on it. */
+ if (*string == '$')
+ {
+ handle_parser_directive (&string[1]);
+ return;
+ }
+
+ /* If we are supposed to be skipping parsing right now, then do it. */
+ if (parsing_conditionalized_out)
+ return;
+
+ i = 0;
+ /* If this keyname is a complex key expression surrounded by quotes,
+ advance to after the matching close quote. */
+ if (*string == '"')
+ {
+ for (i = 1; c = string[i]; i++)
+ {
+ if (c == '"' && string[i - 1] != '\\')
+ break;
+ }
+ }
+
+ /* Advance to the colon (:) or whitespace which separates the two objects. */
+ for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ );
+
+ /* Mark the end of the command (or keyname). */
+ if (string[i])
+ string[i++] = '\0';
+
+ /* If this is a command to set a variable, then do that. */
+ if (stricmp (string, "set") == 0)
+ {
+ char *var = string + i;
+ char *value;
+
+ /* Make VAR point to start of variable name. */
+ while (*var && whitespace (*var)) var++;
+
+ /* Make value point to start of value string. */
+ value = var;
+ while (*value && !whitespace (*value)) value++;
+ if (*value)
+ *value++ = '\0';
+ while (*value && whitespace (*value)) value++;
+
+ rl_variable_bind (var, value);
+ return;
+ }
+
+ /* Skip any whitespace between keyname and funname. */
+ for (; string[i] && whitespace (string[i]); i++);
+ funname = &string[i];
+
+ /* Now isolate funname.
+ For straight function names just look for whitespace, since
+ that will signify the end of the string. But this could be a
+ macro definition. In that case, the string is quoted, so skip
+ to the matching delimiter. */
+ if (*funname == '\'' || *funname == '"')
+ {
+ int delimiter = string[i++];
+
+ for (; c = string[i]; i++)
+ {
+ if (c == delimiter && string[i - 1] != '\\')
+ break;
+ }
+ if (c)
+ i++;
+ }
+
+ /* Advance to the end of the string. */
+ for (; string[i] && !whitespace (string[i]); i++);
+
+ /* No extra whitespace at the end of the string. */
+ string[i] = '\0';
+
+ /* If this is a new-style key-binding, then do the binding with
+ rl_set_key (). Otherwise, let the older code deal with it. */
+ if (*string == '"')
+ {
+ char *seq = (char *)alloca (1 + strlen (string));
+ register int j, k = 0;
+
+ for (j = 1; string[j]; j++)
+ {
+ if (string[j] == '"' && string[j - 1] != '\\')
+ break;
+
+ seq[k++] = string[j];
+ }
+ seq[k] = '\0';
+
+ /* Binding macro? */
+ if (*funname == '\'' || *funname == '"')
+ {
+ j = strlen (funname);
+
+ if (j && funname[j - 1] == *funname)
+ funname[j - 1] = '\0';
+
+ rl_macro_bind (seq, &funname[1], keymap);
+ }
+ else
+ rl_set_key (seq, rl_named_function (funname), keymap);
+
+ return;
+ }
+
+ /* Get the actual character we want to deal with. */
+ kname = rindex (string, '-');
+ if (!kname)
+ kname = string;
+ else
+ kname++;
+
+ key = glean_key_from_name (kname);
+
+ /* Add in control and meta bits. */
+ if (substring_member_of_array (string, possible_control_prefixes))
+ key = CTRL (to_upper (key));
+
+ if (substring_member_of_array (string, possible_meta_prefixes))
+ key = META (key);
+
+ /* Temporary. Handle old-style keyname with macro-binding. */
+ if (*funname == '\'' || *funname == '"')
+ {
+ char seq[2];
+ int fl = strlen (funname);
+
+ seq[0] = key; seq[1] = '\0';
+ if (fl && funname[fl - 1] == *funname)
+ funname[fl - 1] = '\0';
+
+ rl_macro_bind (seq, &funname[1], keymap);
+ }
+ else
+ rl_bind_key (key, rl_named_function (funname));
+}
+
+rl_variable_bind (name, value)
+ char *name, *value;
+{
+ static int strnicmp (), stricmp ();
+
+ if (stricmp (name, "editing-mode") == 0)
+ {
+ if (strnicmp (value, "vi", 2) == 0)
+ {
+#ifdef VI_MODE
+ keymap = vi_insertion_keymap;
+ rl_editing_mode = vi_mode;
+#endif /* VI_MODE */
+ }
+ else if (strnicmp (value, "emacs", 5) == 0)
+ {
+ keymap = emacs_standard_keymap;
+ rl_editing_mode = emacs_mode;
+ }
+ }
+ else if (stricmp (name, "horizontal-scroll-mode") == 0)
+ {
+ if (!*value || stricmp (value, "On") == 0)
+ horizontal_scroll_mode = 1;
+ else
+ horizontal_scroll_mode = 0;
+ }
+}
+
+/* Return the character which matches NAME.
+ For example, `Space' returns ' '. */
+
+typedef struct {
+ char *name;
+ int value;
+} assoc_list;
+
+assoc_list name_key_alist[] = {
+ { "Space", ' ' },
+ { "SPC", ' ' },
+ { "Rubout", 0x7f },
+ { "DEL", 0x7f },
+ { "Tab", 0x09 },
+ { "Newline", '\n' },
+ { "Return", '\r' },
+ { "RET", '\r' },
+ { "LFD", '\n' },
+ { "Escape", '\033' },
+ { "ESC", '\033' },
+
+ { (char *)0x0, 0 }
+};
+
+int
+glean_key_from_name (name)
+ char *name;
+{
+ register int i;
+ static int stricmp ();
+
+ for (i = 0; name_key_alist[i].name; i++)
+ if (stricmp (name, name_key_alist[i].name) == 0)
+ return (name_key_alist[i].value);
+
+ return (*name);
+}
+
+
+/* **************************************************************** */
+/* */
+/* String Utility Functions */
+/* */
+/* **************************************************************** */
+
+/* Return non-zero if any members of ARRAY are a substring in STRING. */
+static int
+substring_member_of_array (string, array)
+ char *string, **array;
+{
+ static char *strindex ();
+
+ while (*array)
+ {
+ if (strindex (string, *array))
+ return (1);
+ array++;
+ }
+ return (0);
+}
+
+/* Whoops, Unix doesn't have strnicmp. */
+
+/* Compare at most COUNT characters from string1 to string2. Case
+ doesn't matter. */
+static int
+strnicmp (string1, string2, count)
+ char *string1, *string2;
+{
+ register char ch1, ch2;
+
+ while (count) {
+ ch1 = *string1++;
+ ch2 = *string2++;
+ if (to_upper(ch1) == to_upper(ch2))
+ count--;
+ else break;
+ }
+ return (count);
+}
+
+/* strcmp (), but caseless. */
+static int
+stricmp (string1, string2)
+ char *string1, *string2;
+{
+ register char ch1, ch2;
+
+ while (*string1 && *string2) {
+ ch1 = *string1++;
+ ch2 = *string2++;
+ if (to_upper(ch1) != to_upper(ch2))
+ return (1);
+ }
+ return (*string1 | *string2);
+}
+
+/* Determine if s2 occurs in s1. If so, return a pointer to the
+ match in s1. The compare is case insensitive. */
+static char *
+strindex (s1, s2)
+ register char *s1, *s2;
+{
+ register int i, l = strlen (s2);
+ register int len = strlen (s1);
+
+ for (i = 0; (len - i) >= l; i++)
+ if (strnicmp (&s1[i], s2, l) == 0)
+ return (s1 + i);
+ return ((char *)NULL);
+}
+
+
+#ifdef STATIC_MALLOC
+
+/* **************************************************************** */
+/* */
+/* xmalloc and xrealloc () */
+/* */
+/* **************************************************************** */
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ static memory_error_and_abort ();
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ static memory_error_and_abort ();
+ char *temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static
+memory_error_and_abort ()
+{
+ fprintf (stderr, "readline: Out of virtual memory!\n");
+ abort ();
+}
+#endif /* STATIC_MALLOC */
+
+
+/* **************************************************************** */
+/* */
+/* Testing Readline */
+/* */
+/* **************************************************************** */
+
+#ifdef TEST
+
+main ()
+{
+ HIST_ENTRY **history_list ();
+ char *temp = (char *)NULL;
+ char *prompt = "readline% ";
+ int done = 0;
+
+ while (!done)
+ {
+ temp = readline (prompt);
+
+ /* Test for EOF. */
+ if (!temp)
+ exit (1);
+
+ /* If there is anything on the line, print it and remember it. */
+ if (*temp)
+ {
+ fprintf (stderr, "%s\r\n", temp);
+ add_history (temp);
+ }
+
+ /* Check for `command' that we handle. */
+ if (strcmp (temp, "quit") == 0)
+ done = 1;
+
+ if (strcmp (temp, "list") == 0) {
+ HIST_ENTRY **list = history_list ();
+ register int i;
+ if (list) {
+ for (i = 0; list[i]; i++) {
+ fprintf (stderr, "%d: %s\r\n", i, list[i]->line);
+ free (list[i]->line);
+ }
+ free (list);
+ }
+ }
+ free (temp);
+ }
+}
+
+#endif /* TEST */
+
+
+/*
+ * Local variables:
+ * compile-command: "gcc -g -traditional -I. -I.. -DTEST -o readline readline.c keymaps.o funmap.o history.o -ltermcap"
+ * end:
+ */
diff --git a/gnu/usr.bin/gdb/readline/readline.h b/gnu/usr.bin/gdb/readline/readline.h
new file mode 100644
index 0000000..7d7fbe7
--- /dev/null
+++ b/gnu/usr.bin/gdb/readline/readline.h
@@ -0,0 +1,161 @@
+/* Readline.h -- the names of functions callable from within readline. */
+
+#ifndef _READLINE_H_
+#define _READLINE_H_
+
+#include <readline/keymaps.h>
+
+#ifndef __FUNCTION_DEF
+typedef int Function ();
+#define __FUNCTION_DEF
+#endif
+
+/* The functions for manipulating the text of the line within readline.
+Most of these functions are bound to keys by default. */
+extern int
+rl_beg_of_line (), rl_backward (), rl_delete (), rl_end_of_line (),
+rl_forward (), ding (), rl_backward (), rl_newline (), rl_kill_line (),
+rl_clear_screen (), rl_get_next_history (), rl_get_previous_history (),
+rl_quoted_insert (), rl_reverse_search_history (), rl_transpose_chars
+(), rl_unix_line_discard (), rl_quoted_insert (), rl_unix_word_rubout
+(), rl_yank (), rl_rubout (), rl_backward_word (), rl_kill_word (),
+rl_forward_word (), rl_tab_insert (), rl_yank_pop (), rl_yank_nth_arg (),
+rl_backward_kill_word (), rl_backward_kill_line (), rl_transpose_words
+(), rl_complete (), rl_possible_completions (), rl_do_lowercase_version
+(), rl_digit_argument (), rl_universal_argument (), rl_abort (),
+rl_undo_command (), rl_revert_line (), rl_beginning_of_history (),
+rl_end_of_history (), rl_forward_search_history (), rl_insert (),
+rl_upcase_word (), rl_downcase_word (), rl_capitalize_word (),
+rl_restart_output (), rl_re_read_init_file ();
+
+/* These are *both* defined even when VI_MODE is not. */
+extern int rl_vi_editing_mode (), rl_emacs_editing_mode ();
+
+#ifdef VI_MODE
+/* Things for vi mode. */
+extern int rl_vi_movement_mode (), rl_vi_insertion_mode (), rl_vi_arg_digit (),
+rl_vi_prev_word (), rl_vi_next_word (), rl_vi_char_search (),
+rl_vi_eof_maybe (), rl_vi_append_mode (), rl_vi_put (),
+rl_vi_append_eol (), rl_vi_insert_beg (), rl_vi_delete (), rl_vi_comment (),
+rl_vi_first_print (), rl_vi_fword (), rl_vi_fWord (), rl_vi_bword (),
+rl_vi_bWord (), rl_vi_eword (), rl_vi_eWord (), rl_vi_end_word (),
+rl_vi_change_case (), rl_vi_match (), rl_vi_bracktype (), rl_vi_change_char (),
+rl_vi_yank_arg (), rl_vi_search (), rl_vi_search_again (),
+rl_vi_dosearch (), rl_vi_subst (), rl_vi_overstrike (),
+rl_vi_overstrike_delete (), rl_vi_replace(), rl_vi_column (),
+rl_vi_delete_to (), rl_vi_change_to (), rl_vi_yank_to (), rl_vi_complete ();
+#endif /* VI_MODE */
+
+/* Keyboard macro commands. */
+extern int
+rl_start_kbd_macro (), rl_end_kbd_macro (), rl_call_last_kbd_macro ();
+
+/* Maintaining the state of undo. We remember individual deletes and inserts
+ on a chain of things to do. */
+
+/* The actions that undo knows how to undo. Notice that UNDO_DELETE means
+ to insert some text, and UNDO_INSERT means to delete some text. I.e.,
+ the code tells undo what to undo, not how to undo it. */
+enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END };
+
+/* What an element of THE_UNDO_LIST looks like. */
+typedef struct undo_list {
+ struct undo_list *next;
+ int start, end; /* Where the change took place. */
+ char *text; /* The text to insert, if undoing a delete. */
+ enum undo_code what; /* Delete, Insert, Begin, End. */
+} UNDO_LIST;
+
+/* The current undo list for RL_LINE_BUFFER. */
+extern UNDO_LIST *rl_undo_list;
+
+/* The data structure for mapping textual names to code addresses. */
+typedef struct {
+ char *name;
+ Function *function;
+} FUNMAP;
+
+extern FUNMAP **funmap;
+
+/* **************************************************************** */
+/* */
+/* Well Published Variables */
+/* */
+/* **************************************************************** */
+
+/* The name of the calling program. You should initialize this to
+ whatever was in argv[0]. It is used when parsing conditionals. */
+extern char *rl_readline_name;
+
+/* The line buffer that is in use. */
+extern char *rl_line_buffer;
+
+/* The location of point, and end. */
+extern int rl_point, rl_end;
+
+/* The name of the terminal to use. */
+extern char *rl_terminal_name;
+
+/* The input and output streams. */
+extern FILE *rl_instream, *rl_outstream;
+
+/* The basic list of characters that signal a break between words for the
+ completer routine. The contents of this variable is what breaks words
+ in the shell, i.e. "n\"\\'`@$>". */
+extern char *rl_basic_word_break_characters;
+
+/* The list of characters that signal a break between words for
+ rl_complete_internal. The default list is the contents of
+ rl_basic_word_break_characters. */
+extern char *rl_completer_word_break_characters;
+
+/* List of characters that are word break characters, but should be left
+ in TEXT when it is passed to the completion function. The shell uses
+ this to help determine what kind of completing to do. */
+extern char *rl_special_prefixes;
+
+/* Pointer to the generator function for completion_matches ().
+ NULL means to use filename_entry_function (), the default filename
+ completer. */
+extern Function *rl_completion_entry_function;
+
+/* Pointer to alternative function to create matches.
+ Function is called with TEXT, START, and END.
+ START and END are indices in RL_LINE_BUFFER saying what the boundaries
+ of TEXT are.
+ If this function exists and returns NULL then call the value of
+ rl_completion_entry_function to try to match, otherwise use the
+ array of strings returned. */
+extern Function *rl_attempted_completion_function;
+
+/* 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 *rl_tilde_expander;
+
+/* If non-zero, then this is the address of a function to call just
+ before readline_internal () prints the first prompt. */
+extern Function *rl_startup_hook;
+
+/* **************************************************************** */
+/* */
+/* Well Published Functions */
+/* */
+/* **************************************************************** */
+
+/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */
+extern char *readline ();
+
+/* Return an array of strings which are the result of repeatadly calling
+ FUNC with TEXT. */
+extern char **completion_matches ();
+
+/* rl_add_defun (char *name, Function *function, int key)
+ Add NAME to the list of named functions. Make FUNCTION
+ be the function that gets called.
+ If KEY is not -1, then bind it. */
+extern int rl_add_defun ();
+
+#endif /* _READLINE_H_ */
+
diff --git a/gnu/usr.bin/gdb/readline/vi_keymap.c b/gnu/usr.bin/gdb/readline/vi_keymap.c
new file mode 100644
index 0000000..71c7ec8
--- /dev/null
+++ b/gnu/usr.bin/gdb/readline/vi_keymap.c
@@ -0,0 +1,484 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ *
+ * @(#)vi_keymap.c 6.4 (Berkeley) 5/8/91
+ */
+
+/* vi_keymap.c -- the keymap for vi_mode in readline (). */
+
+/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
+
+ This file is part of GNU Readline, a library for reading lines
+ of text with interactive input and history editing.
+
+ Readline is free software; you can 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.
+
+ Readline is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Readline; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef FILE
+#include <stdio.h>
+#endif /* FILE */
+
+#include "readline.h"
+
+extern KEYMAP_ENTRY_ARRAY vi_escape_keymap;
+
+/* The keymap arrays for handling vi mode. */
+KEYMAP_ENTRY_ARRAY vi_movement_keymap = {
+
+ /* The regular control keys come first. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, (Function *)0x0 }, /* Control-a */
+ { ISFUNC, (Function *)0x0 }, /* Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Control-c */
+ { ISFUNC, rl_vi_eof_maybe }, /* Control-d */
+ { ISFUNC, rl_emacs_editing_mode }, /* Control-e */
+ { ISFUNC, (Function *)0x0 }, /* Control-f */
+ { ISFUNC, rl_abort }, /* Control-g */
+ { ISFUNC, rl_backward }, /* Control-h */
+ { ISFUNC, (Function *)0x0 }, /* Control-i */
+ { ISFUNC, rl_newline }, /* Control-j */
+ { ISFUNC, rl_kill_line }, /* Control-k */
+ { ISFUNC, rl_clear_screen }, /* Control-l */
+ { ISFUNC, rl_newline }, /* Control-m */
+ { ISFUNC, rl_get_next_history }, /* Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Control-o */
+ { ISFUNC, rl_get_previous_history }, /* Control-p */
+ { ISFUNC, rl_quoted_insert }, /* Control-q */
+ { ISFUNC, rl_reverse_search_history }, /* Control-r */
+ { ISFUNC, rl_forward_search_history }, /* Control-s */
+ { ISFUNC, rl_transpose_chars }, /* Control-t */
+ { ISFUNC, rl_unix_line_discard }, /* Control-u */
+ { ISFUNC, rl_quoted_insert }, /* Control-v */
+ { ISFUNC, rl_unix_word_rubout }, /* Control-w */
+ { ISFUNC, (Function *)0x0 }, /* Control-x */
+ { ISFUNC, rl_yank }, /* Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Control-z */
+
+ { ISKMAP, (Function *)vi_escape_keymap }, /* Control-[ */
+ { ISFUNC, (Function *)0x0 }, /* Control-\ */
+ { ISFUNC, (Function *)0x0 }, /* Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Control-^ */
+ { ISFUNC, rl_undo_command }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, rl_forward }, /* SPACE */
+ { ISFUNC, (Function *)0x0 }, /* ! */
+ { ISFUNC, (Function *)0x0 }, /* " */
+ { ISFUNC, rl_vi_comment }, /* # */
+ { ISFUNC, rl_end_of_line }, /* $ */
+ { ISFUNC, rl_vi_match }, /* % */
+ { ISFUNC, (Function *)0x0 }, /* & */
+ { ISFUNC, (Function *)0x0 }, /* ' */
+ { ISFUNC, (Function *)0x0 }, /* ( */
+ { ISFUNC, (Function *)0x0 }, /* ) */
+ { ISFUNC, rl_vi_complete }, /* * */
+ { ISFUNC, rl_get_previous_history}, /* + */
+ { ISFUNC, rl_vi_char_search }, /* , */
+ { ISFUNC, rl_get_next_history }, /* - */
+ { ISFUNC, (Function *)0x0 }, /* . */
+ { ISFUNC, rl_vi_search }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, rl_vi_arg_digit }, /* 0 */
+ { ISFUNC, rl_vi_arg_digit }, /* 1 */
+ { ISFUNC, rl_vi_arg_digit }, /* 2 */
+ { ISFUNC, rl_vi_arg_digit }, /* 3 */
+ { ISFUNC, rl_vi_arg_digit }, /* 4 */
+ { ISFUNC, rl_vi_arg_digit }, /* 5 */
+ { ISFUNC, rl_vi_arg_digit }, /* 6 */
+ { ISFUNC, rl_vi_arg_digit }, /* 7 */
+ { ISFUNC, rl_vi_arg_digit }, /* 8 */
+ { ISFUNC, rl_vi_arg_digit }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* : */
+ { ISFUNC, rl_vi_char_search }, /* ; */
+ { ISFUNC, (Function *)0x0 }, /* < */
+ { ISFUNC, (Function *)0x0 }, /* = */
+ { ISFUNC, (Function *)0x0 }, /* > */
+ { ISFUNC, rl_vi_search }, /* ? */
+ { ISFUNC, (Function *)0x0 }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_vi_append_eol }, /* A */
+ { ISFUNC, rl_vi_prev_word}, /* B */
+ { ISFUNC, rl_vi_change_to }, /* C */
+ { ISFUNC, rl_vi_delete_to }, /* D */
+ { ISFUNC, rl_vi_end_word }, /* E */
+ { ISFUNC, rl_vi_char_search }, /* F */
+ { ISFUNC, (Function *)0x0 }, /* G */
+ { ISFUNC, (Function *)0x0 }, /* H */
+ { ISFUNC, rl_vi_insert_beg }, /* I */
+ { ISFUNC, (Function *)0x0 }, /* J */
+ { ISFUNC, (Function *)0x0 }, /* K */
+ { ISFUNC, (Function *)0x0 }, /* L */
+ { ISFUNC, (Function *)0x0 }, /* M */
+ { ISFUNC, rl_vi_search_again }, /* N */
+ { ISFUNC, (Function *)0x0 }, /* O */
+ { ISFUNC, rl_vi_put }, /* P */
+ { ISFUNC, (Function *)0x0 }, /* Q */
+ { ISFUNC, rl_vi_replace }, /* R */
+ { ISFUNC, rl_vi_subst }, /* S */
+ { ISFUNC, rl_vi_char_search }, /* T */
+ { ISFUNC, rl_revert_line }, /* U */
+ { ISFUNC, (Function *)0x0 }, /* V */
+ { ISFUNC, rl_vi_next_word }, /* W */
+ { ISFUNC, rl_rubout }, /* X */
+ { ISFUNC, rl_vi_yank_to }, /* Y */
+ { ISFUNC, (Function *)0x0 }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* [ */
+ { ISFUNC, (Function *)0x0 }, /* \ */
+ { ISFUNC, (Function *)0x0 }, /* ] */
+ { ISFUNC, rl_vi_first_print }, /* ^ */
+ { ISFUNC, rl_vi_yank_arg }, /* _ */
+ { ISFUNC, (Function *)0x0 }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, rl_vi_append_mode }, /* a */
+ { ISFUNC, rl_vi_prev_word }, /* b */
+ { ISFUNC, rl_vi_change_to }, /* c */
+ { ISFUNC, rl_vi_delete_to }, /* d */
+ { ISFUNC, rl_vi_end_word }, /* e */
+ { ISFUNC, rl_vi_char_search }, /* f */
+ { ISFUNC, (Function *)0x0 }, /* g */
+ { ISFUNC, rl_backward }, /* h */
+ { ISFUNC, rl_vi_insertion_mode }, /* i */
+ { ISFUNC, rl_get_next_history }, /* j */
+ { ISFUNC, rl_get_previous_history }, /* k */
+ { ISFUNC, rl_forward }, /* l */
+ { ISFUNC, (Function *)0x0 }, /* m */
+ { ISFUNC, rl_vi_search_again }, /* n */
+ { ISFUNC, (Function *)0x0 }, /* o */
+ { ISFUNC, rl_vi_put }, /* p */
+ { ISFUNC, (Function *)0x0 }, /* q */
+ { ISFUNC, rl_vi_change_char }, /* r */
+ { ISFUNC, rl_vi_subst }, /* s */
+ { ISFUNC, rl_vi_char_search }, /* t */
+ { ISFUNC, rl_undo_command }, /* u */
+ { ISFUNC, (Function *)0x0 }, /* v */
+ { ISFUNC, rl_vi_next_word }, /* w */
+ { ISFUNC, rl_vi_delete }, /* x */
+ { ISFUNC, rl_vi_yank_to }, /* y */
+ { ISFUNC, (Function *)0x0 }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* { */
+ { ISFUNC, rl_vi_column }, /* | */
+ { ISFUNC, (Function *)0x0 }, /* } */
+ { ISFUNC, rl_vi_change_case }, /* ~ */
+ { ISFUNC, rl_backward } /* RUBOUT */
+};
+
+
+KEYMAP_ENTRY_ARRAY vi_insertion_keymap = {
+
+ /* The regular control keys come first. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, rl_insert }, /* Control-a */
+ { ISFUNC, rl_insert }, /* Control-b */
+ { ISFUNC, rl_insert }, /* Control-c */
+ { ISFUNC, rl_vi_eof_maybe }, /* Control-d */
+ { ISFUNC, rl_insert }, /* Control-e */
+ { ISFUNC, rl_insert }, /* Control-f */
+ { ISFUNC, rl_insert }, /* Control-g */
+ { ISFUNC, rl_rubout }, /* Control-h */
+ { ISFUNC, rl_complete }, /* Control-i */
+ { ISFUNC, rl_newline }, /* Control-j */
+ { ISFUNC, rl_insert }, /* Control-k */
+ { ISFUNC, rl_insert }, /* Control-l */
+ { ISFUNC, rl_newline }, /* Control-m */
+ { ISFUNC, rl_insert }, /* Control-n */
+ { ISFUNC, rl_insert }, /* Control-o */
+ { ISFUNC, rl_insert }, /* Control-p */
+ { ISFUNC, rl_insert }, /* Control-q */
+ { ISFUNC, rl_reverse_search_history }, /* Control-r */
+ { ISFUNC, rl_forward_search_history }, /* Control-s */
+ { ISFUNC, rl_transpose_chars }, /* Control-t */
+ { ISFUNC, rl_unix_line_discard }, /* Control-u */
+ { ISFUNC, rl_quoted_insert }, /* Control-v */
+ { ISFUNC, rl_unix_word_rubout }, /* Control-w */
+ { ISFUNC, rl_insert }, /* Control-x */
+ { ISFUNC, rl_yank }, /* Control-y */
+ { ISFUNC, rl_insert }, /* Control-z */
+
+ { ISFUNC, rl_vi_movement_mode }, /* Control-[ */
+ { ISFUNC, rl_insert }, /* Control-\ */
+ { ISFUNC, rl_insert }, /* Control-] */
+ { ISFUNC, rl_insert }, /* Control-^ */
+ { ISFUNC, rl_undo_command }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, rl_insert }, /* SPACE */
+ { ISFUNC, rl_insert }, /* ! */
+ { ISFUNC, rl_insert }, /* " */
+ { ISFUNC, rl_insert }, /* # */
+ { ISFUNC, rl_insert }, /* $ */
+ { ISFUNC, rl_insert }, /* % */
+ { ISFUNC, rl_insert }, /* & */
+ { ISFUNC, rl_insert }, /* ' */
+ { ISFUNC, rl_insert }, /* ( */
+ { ISFUNC, rl_insert }, /* ) */
+ { ISFUNC, rl_insert }, /* * */
+ { ISFUNC, rl_insert }, /* + */
+ { ISFUNC, rl_insert }, /* , */
+ { ISFUNC, rl_insert }, /* - */
+ { ISFUNC, rl_insert }, /* . */
+ { ISFUNC, rl_insert }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, rl_insert }, /* 0 */
+ { ISFUNC, rl_insert }, /* 1 */
+ { ISFUNC, rl_insert }, /* 2 */
+ { ISFUNC, rl_insert }, /* 3 */
+ { ISFUNC, rl_insert }, /* 4 */
+ { ISFUNC, rl_insert }, /* 5 */
+ { ISFUNC, rl_insert }, /* 6 */
+ { ISFUNC, rl_insert }, /* 7 */
+ { ISFUNC, rl_insert }, /* 8 */
+ { ISFUNC, rl_insert }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, rl_insert }, /* : */
+ { ISFUNC, rl_insert }, /* ; */
+ { ISFUNC, rl_insert }, /* < */
+ { ISFUNC, rl_insert }, /* = */
+ { ISFUNC, rl_insert }, /* > */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_insert }, /* A */
+ { ISFUNC, rl_insert }, /* B */
+ { ISFUNC, rl_insert }, /* C */
+ { ISFUNC, rl_insert }, /* D */
+ { ISFUNC, rl_insert }, /* E */
+ { ISFUNC, rl_insert }, /* F */
+ { ISFUNC, rl_insert }, /* G */
+ { ISFUNC, rl_insert }, /* H */
+ { ISFUNC, rl_insert }, /* I */
+ { ISFUNC, rl_insert }, /* J */
+ { ISFUNC, rl_insert }, /* K */
+ { ISFUNC, rl_insert }, /* L */
+ { ISFUNC, rl_insert }, /* M */
+ { ISFUNC, rl_insert }, /* N */
+ { ISFUNC, rl_insert }, /* O */
+ { ISFUNC, rl_insert }, /* P */
+ { ISFUNC, rl_insert }, /* Q */
+ { ISFUNC, rl_insert }, /* R */
+ { ISFUNC, rl_insert }, /* S */
+ { ISFUNC, rl_insert }, /* T */
+ { ISFUNC, rl_insert }, /* U */
+ { ISFUNC, rl_insert }, /* V */
+ { ISFUNC, rl_insert }, /* W */
+ { ISFUNC, rl_insert }, /* X */
+ { ISFUNC, rl_insert }, /* Y */
+ { ISFUNC, rl_insert }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, rl_insert }, /* [ */
+ { ISFUNC, rl_insert }, /* \ */
+ { ISFUNC, rl_insert }, /* ] */
+ { ISFUNC, rl_insert }, /* ^ */
+ { ISFUNC, rl_insert }, /* _ */
+ { ISFUNC, rl_insert }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, rl_insert }, /* a */
+ { ISFUNC, rl_insert }, /* b */
+ { ISFUNC, rl_insert }, /* c */
+ { ISFUNC, rl_insert }, /* d */
+ { ISFUNC, rl_insert }, /* e */
+ { ISFUNC, rl_insert }, /* f */
+ { ISFUNC, rl_insert }, /* g */
+ { ISFUNC, rl_insert }, /* h */
+ { ISFUNC, rl_insert }, /* i */
+ { ISFUNC, rl_insert }, /* j */
+ { ISFUNC, rl_insert }, /* k */
+ { ISFUNC, rl_insert }, /* l */
+ { ISFUNC, rl_insert }, /* m */
+ { ISFUNC, rl_insert }, /* n */
+ { ISFUNC, rl_insert }, /* o */
+ { ISFUNC, rl_insert }, /* p */
+ { ISFUNC, rl_insert }, /* q */
+ { ISFUNC, rl_insert }, /* r */
+ { ISFUNC, rl_insert }, /* s */
+ { ISFUNC, rl_insert }, /* t */
+ { ISFUNC, rl_insert }, /* u */
+ { ISFUNC, rl_insert }, /* v */
+ { ISFUNC, rl_insert }, /* w */
+ { ISFUNC, rl_insert }, /* x */
+ { ISFUNC, rl_insert }, /* y */
+ { ISFUNC, rl_insert }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, rl_insert }, /* { */
+ { ISFUNC, rl_insert }, /* | */
+ { ISFUNC, rl_insert }, /* } */
+ { ISFUNC, rl_insert }, /* ~ */
+ { ISFUNC, rl_rubout } /* RUBOUT */
+};
+
+KEYMAP_ENTRY_ARRAY vi_escape_keymap = {
+
+ /* The regular control keys come first. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, (Function *)0x0 }, /* Control-a */
+ { ISFUNC, (Function *)0x0 }, /* Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Control-c */
+ { ISFUNC, (Function *)0x0 }, /* Control-d */
+ { ISFUNC, (Function *)0x0 }, /* Control-e */
+ { ISFUNC, (Function *)0x0 }, /* Control-f */
+ { ISFUNC, (Function *)0x0 }, /* Control-g */
+ { ISFUNC, (Function *)0x0 }, /* Control-h */
+ { ISFUNC, rl_tab_insert}, /* Control-i */
+ { ISFUNC, rl_emacs_editing_mode}, /* Control-j */
+ { ISFUNC, rl_kill_line }, /* Control-k */
+ { ISFUNC, (Function *)0x0 }, /* Control-l */
+ { ISFUNC, rl_emacs_editing_mode}, /* Control-m */
+ { ISFUNC, (Function *)0x0 }, /* Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Control-o */
+ { ISFUNC, (Function *)0x0 }, /* Control-p */
+ { ISFUNC, (Function *)0x0 }, /* Control-q */
+ { ISFUNC, (Function *)0x0 }, /* Control-r */
+ { ISFUNC, (Function *)0x0 }, /* Control-s */
+ { ISFUNC, (Function *)0x0 }, /* Control-t */
+ { ISFUNC, (Function *)0x0 }, /* Control-u */
+ { ISFUNC, (Function *)0x0 }, /* Control-v */
+ { ISFUNC, (Function *)0x0 }, /* Control-w */
+ { ISFUNC, (Function *)0x0 }, /* Control-x */
+ { ISFUNC, (Function *)0x0 }, /* Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Control-z */
+
+ { ISFUNC, rl_vi_movement_mode }, /* Control-[ */
+ { ISFUNC, (Function *)0x0 }, /* Control-\ */
+ { ISFUNC, (Function *)0x0 }, /* Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Control-^ */
+ { ISFUNC, rl_undo_command }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, (Function *)0x0 }, /* SPACE */
+ { ISFUNC, (Function *)0x0 }, /* ! */
+ { ISFUNC, (Function *)0x0 }, /* " */
+ { ISFUNC, (Function *)0x0 }, /* # */
+ { ISFUNC, (Function *)0x0 }, /* $ */
+ { ISFUNC, (Function *)0x0 }, /* % */
+ { ISFUNC, (Function *)0x0 }, /* & */
+ { ISFUNC, (Function *)0x0 }, /* ' */
+ { ISFUNC, (Function *)0x0 }, /* ( */
+ { ISFUNC, (Function *)0x0 }, /* ) */
+ { ISFUNC, (Function *)0x0 }, /* * */
+ { ISFUNC, (Function *)0x0 }, /* + */
+ { ISFUNC, (Function *)0x0 }, /* , */
+ { ISFUNC, (Function *)0x0 }, /* - */
+ { ISFUNC, (Function *)0x0 }, /* . */
+ { ISFUNC, (Function *)0x0 }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, rl_vi_arg_digit }, /* 0 */
+ { ISFUNC, rl_vi_arg_digit }, /* 1 */
+ { ISFUNC, rl_vi_arg_digit }, /* 2 */
+ { ISFUNC, rl_vi_arg_digit }, /* 3 */
+ { ISFUNC, rl_vi_arg_digit }, /* 4 */
+ { ISFUNC, rl_vi_arg_digit }, /* 5 */
+ { ISFUNC, rl_vi_arg_digit }, /* 6 */
+ { ISFUNC, rl_vi_arg_digit }, /* 7 */
+ { ISFUNC, rl_vi_arg_digit }, /* 8 */
+ { ISFUNC, rl_vi_arg_digit }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* : */
+ { ISFUNC, (Function *)0x0 }, /* ; */
+ { ISFUNC, (Function *)0x0 }, /* < */
+ { ISFUNC, (Function *)0x0 }, /* = */
+ { ISFUNC, (Function *)0x0 }, /* > */
+ { ISFUNC, (Function *)0x0 }, /* ? */
+ { ISFUNC, (Function *)0x0 }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_do_lowercase_version }, /* A */
+ { ISFUNC, rl_do_lowercase_version }, /* B */
+ { ISFUNC, rl_do_lowercase_version }, /* C */
+ { ISFUNC, rl_do_lowercase_version }, /* D */
+ { ISFUNC, rl_do_lowercase_version }, /* E */
+ { ISFUNC, rl_do_lowercase_version }, /* F */
+ { ISFUNC, rl_do_lowercase_version }, /* G */
+ { ISFUNC, rl_do_lowercase_version }, /* H */
+ { ISFUNC, rl_do_lowercase_version }, /* I */
+ { ISFUNC, rl_do_lowercase_version }, /* J */
+ { ISFUNC, rl_do_lowercase_version }, /* K */
+ { ISFUNC, rl_do_lowercase_version }, /* L */
+ { ISFUNC, rl_do_lowercase_version }, /* M */
+ { ISFUNC, rl_do_lowercase_version }, /* N */
+ { ISFUNC, rl_do_lowercase_version }, /* O */
+ { ISFUNC, rl_do_lowercase_version }, /* P */
+ { ISFUNC, rl_do_lowercase_version }, /* Q */
+ { ISFUNC, rl_do_lowercase_version }, /* R */
+ { ISFUNC, rl_do_lowercase_version }, /* S */
+ { ISFUNC, rl_do_lowercase_version }, /* T */
+ { ISFUNC, rl_do_lowercase_version }, /* U */
+ { ISFUNC, rl_do_lowercase_version }, /* V */
+ { ISFUNC, rl_do_lowercase_version }, /* W */
+ { ISFUNC, rl_do_lowercase_version }, /* X */
+ { ISFUNC, rl_do_lowercase_version }, /* Y */
+ { ISFUNC, rl_do_lowercase_version }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* [ */
+ { ISFUNC, (Function *)0x0 }, /* \ */
+ { ISFUNC, (Function *)0x0 }, /* ] */
+ { ISFUNC, (Function *)0x0 }, /* ^ */
+ { ISFUNC, (Function *)0x0 }, /* _ */
+ { ISFUNC, (Function *)0x0 }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, (Function *)0x0 }, /* a */
+ { ISFUNC, (Function *)0x0 }, /* b */
+ { ISFUNC, (Function *)0x0 }, /* c */
+ { ISFUNC, (Function *)0x0 }, /* d */
+ { ISFUNC, (Function *)0x0 }, /* e */
+ { ISFUNC, (Function *)0x0 }, /* f */
+ { ISFUNC, (Function *)0x0 }, /* g */
+ { ISFUNC, (Function *)0x0 }, /* h */
+ { ISFUNC, (Function *)0x0 }, /* i */
+ { ISFUNC, (Function *)0x0 }, /* j */
+ { ISFUNC, (Function *)0x0 }, /* k */
+ { ISFUNC, (Function *)0x0 }, /* l */
+ { ISFUNC, (Function *)0x0 }, /* m */
+ { ISFUNC, (Function *)0x0 }, /* n */
+ { ISFUNC, (Function *)0x0 }, /* o */
+ { ISFUNC, (Function *)0x0 }, /* p */
+ { ISFUNC, (Function *)0x0 }, /* q */
+ { ISFUNC, (Function *)0x0 }, /* r */
+ { ISFUNC, (Function *)0x0 }, /* s */
+ { ISFUNC, (Function *)0x0 }, /* t */
+ { ISFUNC, (Function *)0x0 }, /* u */
+ { ISFUNC, (Function *)0x0 }, /* v */
+ { ISFUNC, (Function *)0x0 }, /* w */
+ { ISFUNC, (Function *)0x0 }, /* x */
+ { ISFUNC, (Function *)0x0 }, /* y */
+ { ISFUNC, (Function *)0x0 }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* { */
+ { ISFUNC, (Function *)0x0 }, /* | */
+ { ISFUNC, (Function *)0x0 }, /* } */
+ { ISFUNC, (Function *)0x0 }, /* ~ */
+ { ISFUNC, rl_backward_kill_word } /* RUBOUT */
+};
diff --git a/gnu/usr.bin/gdb/readline/vi_mode.c b/gnu/usr.bin/gdb/readline/vi_mode.c
new file mode 100644
index 0000000..3a13cc6
--- /dev/null
+++ b/gnu/usr.bin/gdb/readline/vi_mode.c
@@ -0,0 +1,875 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ *
+ * @(#)vi_mode.c 6.4 (Berkeley) 5/8/91
+ */
+
+/* vi_mode.c -- A vi emulation mode for Bash.
+ Mostly written by Jeff Sparkes (jeff1@????).
+ */
+
+
+/* **************************************************************** */
+/* */
+/* VI Emulation Mode */
+/* */
+/* **************************************************************** */
+
+/* Last string searched for from `/' or `?'. */
+static char *vi_last_search = (char *)NULL;
+static int vi_histpos;
+
+/* *** UNCLEAN *** */
+/* Command keys which do movement for xxx_to commands. */
+static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
+
+/* Keymap used for vi replace characters. Created dynamically since
+ rarely used. */
+static Keymap vi_replace_map = (Keymap)NULL;
+
+/* The number of characters inserted in the last replace operation. */
+static vi_replace_count = 0;
+
+/* Yank the nth arg from the previous line into this line at point. */
+rl_vi_yank_arg (count)
+ int count;
+{
+ rl_yank_nth_arg (count);
+}
+
+/* Search again for the last thing searched for. */
+rl_vi_search_again (ignore, key)
+ int ignore, key;
+{
+ switch (key)
+ {
+ case 'n':
+ rl_vi_dosearch (vi_last_search, -1);
+ break;
+
+ case 'N':
+ rl_vi_dosearch (vi_last_search, 1);
+ break;
+ }
+}
+
+/* Do a vi style search. */
+rl_vi_search (count, key)
+ int count, key;
+{
+ int dir, c;
+ char *p;
+
+ switch (key)
+ {
+ case '?':
+ dir = 1;
+ break;
+
+ case '/':
+ dir = -1;
+ break;
+
+ default:
+ ding ();
+ return;
+ }
+
+ vi_histpos = where_history ();
+ maybe_save_line ();
+
+ /* Reuse the line input buffer to read the search string. */
+ the_line[0] = 0;
+ rl_end = rl_point = 0;
+ p = (char *)alloca (2 + (rl_prompt ? strlen (rl_prompt) : 0));
+
+ sprintf (p, "%s%c", rl_prompt ? rl_prompt : "", key);
+
+ rl_message (p);
+
+ while (c = rl_read_key (in_stream))
+ {
+ switch (c)
+ {
+ case CTRL('W'):
+ case CTRL('U'):
+ case CTRL('H'):
+ case RUBOUT:
+ rl_dispatch (c, keymap);
+ break;
+
+ case ESC:
+ case RETURN:
+ case NEWLINE:
+ goto dosearch;
+ break;
+
+ case CTRL('C'):
+ maybe_unsave_line ();
+ rl_clear_message ();
+ rl_point = 0;
+ ding ();
+ return;
+
+ default:
+ rl_insert (1, c);
+ break;
+ }
+ rl_redisplay ();
+ }
+ dosearch:
+ if (vi_last_search)
+ free (vi_last_search);
+
+ vi_last_search = savestring (the_line);
+ rl_vi_dosearch (the_line, dir);
+}
+
+rl_vi_dosearch (string, dir)
+ char *string;
+ int dir;
+{
+ int old, save = vi_histpos;
+ HIST_ENTRY *h;
+
+ if (string == 0 || *string == 0 || vi_histpos < 0)
+ {
+ ding ();
+ return;
+ }
+
+ if ((save = history_search_pos (string, dir, vi_histpos + dir)) == -1)
+ {
+ maybe_unsave_line ();
+ rl_clear_message ();
+ rl_point = 0;
+ ding ();
+ return;
+ }
+
+ vi_histpos = save;
+
+ old = where_history ();
+ history_set_pos (vi_histpos);
+ h = current_history ();
+ history_set_pos (old);
+
+ strcpy (the_line, h->line);
+ rl_undo_list = (UNDO_LIST *)h->data;
+ rl_end = strlen (the_line);
+ rl_point = 0;
+ rl_clear_message ();
+}
+
+/* Completion, from vi's point of view. */
+rl_vi_complete (ignore, key)
+ int ignore, key;
+{
+ if (!whitespace (the_line[rl_point]))
+ {
+ rl_vi_end_word (1, 'E');
+ rl_point++;
+ }
+ rl_complete_internal ('*');
+ rl_vi_insertion_mode ();
+}
+
+/* Previous word in vi mode. */
+rl_vi_prev_word (count, key)
+ int count, key;
+{
+ if (count < 0)
+ {
+ rl_vi_next_word (-count, key);
+ return;
+ }
+
+ if (uppercase_p (key))
+ rl_vi_bWord (count);
+ else
+ rl_vi_bword (count);
+}
+
+/* Next word in vi mode. */
+rl_vi_next_word (count, key)
+ int count;
+{
+ if (count < 0)
+ {
+ rl_vi_prev_word (-count, key);
+ return;
+ }
+
+ if (uppercase_p (key))
+ rl_vi_fWord (count);
+ else
+ rl_vi_fword (count);
+}
+
+/* Move to the end of the ?next? word. */
+rl_vi_end_word (count, key)
+ int count, key;
+{
+ if (count < 0)
+ {
+ ding ();
+ return;
+ }
+
+ if (uppercase_p (key))
+ rl_vi_eWord (count);
+ else
+ rl_vi_eword (count);
+}
+
+/* Move forward a word the way that 'W' does. */
+rl_vi_fWord (count)
+ int count;
+{
+ while (count-- && rl_point < (rl_end - 1))
+ {
+ /* Skip until whitespace. */
+ while (!whitespace (the_line[rl_point]) && rl_point < rl_end)
+ rl_point++;
+
+ /* Now skip whitespace. */
+ while (whitespace (the_line[rl_point]) && rl_point < rl_end)
+ rl_point++;
+ }
+}
+
+rl_vi_bWord (count)
+ int count;
+{
+ while (count-- && rl_point > 0)
+ {
+ while (rl_point-- >= 0 && whitespace (the_line[rl_point]));
+ while (rl_point >= 0 && !whitespace (the_line[rl_point]))
+ rl_point--;
+ rl_point++;
+ }
+}
+
+rl_vi_eWord (count)
+ int count;
+{
+ while (count -- && rl_point < (rl_end - 1))
+ {
+ while (rl_point++ < rl_end && whitespace (the_line[rl_point]));
+ while (rl_point++ < rl_end && !whitespace (the_line[rl_point]));
+ rl_point--;
+ }
+}
+
+rl_vi_fword (count)
+ int count;
+{
+ while (count -- && rl_point < (rl_end - 1))
+ {
+ if (isident (the_line[rl_point]))
+ {
+ while (isident (the_line[rl_point]) && rl_point < rl_end)
+ rl_point += 1;
+ }
+ else if (!whitespace (the_line[rl_point]))
+ {
+ while (!isident (the_line[rl_point]) &&
+ !whitespace (the_line[rl_point]) && rl_point < rl_end)
+ rl_point += 1;
+ }
+
+ while (whitespace (the_line[rl_point]) && rl_point < rl_end)
+ rl_point++;
+ }
+}
+
+rl_vi_bword (count)
+ int count;
+{
+ while (count -- && rl_point > 0)
+ {
+ while (--rl_point > 0 && whitespace (the_line[rl_point]));
+ if (rl_point > 0)
+ {
+ if (isident (the_line[rl_point]))
+ while (--rl_point >= 0 && isident (the_line[rl_point]));
+ else
+ while (--rl_point >= 0 && !isident (the_line[rl_point]) &&
+ !whitespace (the_line[rl_point]));
+ rl_point++;
+ }
+ }
+}
+
+rl_vi_eword (count)
+ int count;
+{
+ while (count -- && rl_point < rl_end - 1)
+ {
+ while (++rl_point < rl_end && whitespace (the_line[rl_point]));
+
+ if (rl_point < rl_end)
+ {
+ if (isident (the_line[rl_point]))
+ while (++rl_point < rl_end && isident (the_line[rl_point]));
+ else
+ while (++rl_point < rl_end && !isident (the_line[rl_point])
+ && !whitespace (the_line[rl_point]));
+ rl_point--;
+ }
+ }
+}
+
+rl_vi_insert_beg ()
+{
+ rl_beg_of_line ();
+ rl_vi_insertion_mode ();
+ return 0;
+}
+
+rl_vi_append_mode ()
+{
+ if (rl_point < rl_end)
+ rl_point += 1;
+ rl_vi_insertion_mode ();
+ return 0;
+}
+
+rl_vi_append_eol ()
+{
+ rl_end_of_line ();
+ rl_vi_append_mode ();
+ return 0;
+}
+
+/* What to do in the case of C-d. */
+rl_vi_eof_maybe (count, c)
+ int count, c;
+{
+ rl_newline (1, '\n');
+}
+
+/* Insertion mode stuff. */
+
+/* Switching from one mode to the other really just involves
+ switching keymaps. */
+rl_vi_insertion_mode ()
+{
+ keymap = vi_insertion_keymap;
+}
+
+rl_vi_movement_mode ()
+{
+ if (rl_point > 0)
+ rl_backward (1);
+
+ keymap = vi_movement_keymap;
+ if (vi_doing_insert)
+ {
+ rl_end_undo_group ();
+ vi_doing_insert = 0;
+ }
+}
+
+rl_vi_arg_digit (count, c)
+ int count, c;
+{
+ if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
+ rl_beg_of_line ();
+ else
+ rl_digit_argument (count, c);
+}
+
+/* Doesn't take an arg count in vi */
+rl_vi_change_case (ignore1, ignore2)
+ int ignore1, ignore2;
+{
+ char c = 0;
+
+ if (uppercase_p (the_line[rl_point]))
+ c = to_lower (the_line[rl_point]);
+ else if (lowercase_p (the_line[rl_point]))
+ c = to_upper (the_line[rl_point]);
+
+ /* Vi is kind of strange here. */
+ if (c)
+ {
+ rl_begin_undo_group ();
+ rl_delete (1);
+ rl_insert (1, c);
+ rl_end_undo_group ();
+ rl_vi_check ();
+ }
+ else
+ rl_forward (1);
+}
+
+rl_vi_put (count, key)
+ int count, key;
+{
+ if (!uppercase_p (key))
+ {
+ if(rl_point != rl_end)
+ rl_point++;
+ }
+
+ rl_yank ();
+ rl_backward (1);
+}
+
+rl_vi_check ()
+{
+ if (rl_point && rl_point == rl_end)
+ rl_point--;
+}
+
+rl_vi_column (count)
+{
+ if (count > rl_end)
+ rl_end_of_line ();
+ else
+ rl_point = count - 1;
+}
+
+int
+rl_vi_domove ()
+{
+ int c, save;
+
+ rl_mark = rl_point;
+ c = rl_read_key (in_stream);
+
+ if (!member (c, vi_motion))
+ {
+ if (digit (c))
+ {
+ save = rl_numeric_arg;
+ rl_digit_loop1 ();
+ rl_numeric_arg *= save;
+ }
+ else
+ return (-1);
+ }
+
+ rl_dispatch (c, keymap);
+
+ /* No change in position means the command failed. */
+ if (rl_mark == rl_point)
+ return (-1);
+
+ if ((c == 'w' || c == 'W') && rl_point < rl_end)
+ {
+ rl_point--;
+ while((rl_point > 0) && whitespace (the_line[rl_point]))
+ rl_point--;
+ rl_point++;
+ }
+
+ if (rl_mark < rl_point)
+ exchange (rl_point, rl_mark);
+
+ return (0);
+}
+
+/* A simplified loop for vi. Don't dispatch key at end.
+ Don't recognize minus sign? */
+rl_digit_loop1 ()
+{
+ int key, c;
+
+ while (1)
+ {
+ rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg);
+ key = c = rl_read_key ();
+
+ if (keymap[c].type == ISFUNC &&
+ keymap[c].function == rl_universal_argument)
+ {
+ rl_numeric_arg *= 4;
+ continue;
+ }
+ c = UNMETA (c);
+ if (numeric (c))
+ {
+ if (rl_explicit_arg)
+ rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0');
+ else
+ rl_numeric_arg = (c - '0');
+ rl_explicit_arg = 1;
+ }
+ else
+ {
+ rl_clear_message ();
+ rl_stuff_char (key);
+ }
+ }
+}
+
+rl_vi_delete_to (count, key)
+ int count, key;
+{
+ if (uppercase_p (key))
+ rl_stuff_char ('$');
+
+ if (rl_vi_domove ())
+ {
+ ding ();
+ return;
+ }
+
+ rl_kill_text (rl_point, rl_mark);
+}
+
+rl_vi_change_to (count, key)
+ int count, key;
+{
+ if (uppercase_p (key))
+ rl_stuff_char ('$');
+
+ if (rl_vi_domove ())
+ {
+ ding ();
+ return;
+ }
+
+ rl_begin_undo_group ();
+ vi_doing_insert = 1;
+ rl_kill_text (rl_point, rl_mark);
+ rl_vi_insertion_mode ();
+}
+
+rl_vi_yank_to (count, key)
+ int count, key;
+{
+ int save = rl_point;
+
+ if (uppercase_p (key))
+ rl_stuff_char ('$');
+
+ if (rl_vi_domove ())
+ {
+ ding ();
+ return;
+ }
+
+ rl_begin_undo_group ();
+ rl_kill_text (rl_point, rl_mark);
+ rl_end_undo_group ();
+ rl_do_undo ();
+ rl_point = save;
+}
+
+rl_vi_delete (count)
+{
+ if (rl_point >= rl_end - 1)
+ {
+ rl_delete (count);
+ if (rl_point > 0)
+ rl_backward (1);
+ }
+ else
+ rl_delete (count);
+}
+
+/* Turn the current line into a comment in shell history. A ksh function */
+rl_vi_comment ()
+{
+ rl_beg_of_line ();
+ rl_insert_text (": "); /* # doesn't work in interactive mode */
+ rl_redisplay ();
+ rl_newline (1, '\010');
+}
+
+rl_vi_first_print ()
+{
+ rl_back_to_indent ();
+}
+
+rl_back_to_indent (ignore1, ignore2)
+ int ignore1, ignore2;
+{
+ rl_beg_of_line ();
+ while (rl_point < rl_end && whitespace (the_line[rl_point]))
+ rl_point++;
+}
+
+/* NOTE: it is necessary that opposite directions are inverses */
+#define FTO 1 /* forward to */
+#define BTO -1 /* backward to */
+#define FFIND 2 /* forward find */
+#define BFIND -2 /* backward find */
+
+rl_vi_char_search (count, key)
+ int count, key;
+{
+ static char target;
+ static int orig_dir, dir;
+ int pos;
+
+ if (key == ';' || key == ',')
+ dir = (key == ';' ? orig_dir : -orig_dir);
+ else
+ {
+ target = rl_read_key();
+
+ switch (key)
+ {
+ case 't':
+ orig_dir = dir = FTO;
+ break;
+
+ case 'T':
+ orig_dir = dir = BTO;
+ break;
+
+ case 'f':
+ orig_dir = dir = FFIND;
+ break;
+
+ case 'F':
+ orig_dir = dir = BFIND;
+ break;
+ }
+ }
+
+ pos = rl_point;
+
+ if (dir < 0)
+ {
+ pos--;
+ do
+ {
+ if (the_line[pos] == target)
+ {
+ if (dir == BTO)
+ rl_point = pos + 1;
+ else
+ rl_point = pos;
+ return;
+ }
+ }
+ while (pos--);
+
+ if (pos < 0)
+ {
+ ding ();
+ return;
+ }
+ }
+ else
+ { /* dir > 0 */
+ pos++;
+ do
+ {
+ if (the_line[pos] == target)
+ {
+ if (dir == FTO)
+ rl_point = pos - 1;
+ else
+ rl_point = pos;
+ return;
+ }
+ }
+ while (++pos < rl_end);
+
+ if (pos >= (rl_end - 1))
+ ding ();
+ }
+}
+
+/* Match brackets */
+rl_vi_match ()
+{
+ int count = 1, brack, pos;
+
+ pos = rl_point;
+ if ((brack = rl_vi_bracktype (the_line[rl_point])) == 0)
+ {
+ while ((brack = rl_vi_bracktype (the_line[rl_point])) == 0 &&
+ rl_point < rl_end - 1)
+ rl_forward (1);
+
+ if (brack <= 0)
+ {
+ rl_point = pos;
+ ding ();
+ return;
+ }
+ }
+
+ pos = rl_point;
+
+ if (brack < 0)
+ {
+ while (count)
+ {
+ if (--pos >= 0)
+ {
+ int b = rl_vi_bracktype (the_line[pos]);
+ if (b == -brack)
+ count--;
+ else if (b == brack)
+ count++;
+ }
+ else
+ {
+ ding ();
+ return;
+ }
+ }
+ }
+ else
+ { /* brack > 0 */
+ while (count)
+ {
+ if (++pos < rl_end)
+ {
+ int b = rl_vi_bracktype (the_line[pos]);
+ if (b == -brack)
+ count--;
+ else if (b == brack)
+ count++;
+ }
+ else
+ {
+ ding ();
+ return;
+ }
+ }
+ }
+ rl_point = pos;
+}
+
+int
+rl_vi_bracktype (c)
+ int c;
+{
+ switch (c)
+ {
+ case '(': return 1;
+ case ')': return -1;
+ case '[': return 2;
+ case ']': return -2;
+ case '{': return 3;
+ case '}': return -3;
+ default: return 0;
+ }
+}
+
+rl_vi_change_char ()
+{
+ int c;
+
+ c = rl_read_key();
+
+ switch (c)
+ {
+ case '\033':
+ case CTRL('C'):
+ return;
+
+ default:
+ rl_begin_undo_group ();
+ rl_delete (1);
+ rl_insert (1, c);
+ rl_end_undo_group ();
+ break;
+ }
+}
+
+rl_vi_subst (count, key)
+ int count, key;
+{
+ rl_begin_undo_group ();
+ vi_doing_insert = 1;
+
+ if (uppercase_p (key))
+ {
+ rl_beg_of_line ();
+ rl_kill_line (1);
+ }
+ else
+ rl_delete (1);
+
+ rl_vi_insertion_mode ();
+}
+
+rl_vi_overstrike (count, key)
+ int count, key;
+{
+ int i;
+
+ if (vi_doing_insert == 0)
+ {
+ vi_doing_insert = 1;
+ rl_begin_undo_group ();
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ vi_replace_count++;
+ rl_begin_undo_group ();
+
+ if (rl_point < rl_end)
+ {
+ rl_delete (1);
+ rl_insert (1, key);
+ }
+ else
+ rl_insert (1, key);
+
+ rl_end_undo_group ();
+ }
+}
+
+rl_vi_overstrike_delete (count)
+ int count;
+{
+ int i, s;
+
+ for (i = 0; i < count; i++)
+ {
+ if (vi_replace_count == 0)
+ {
+ ding ();
+ break;
+ }
+ s = rl_point;
+
+ if (rl_do_undo ())
+ vi_replace_count--;
+
+ if (rl_point == s)
+ rl_backward (1);
+ }
+
+ if (vi_replace_count == 0 && vi_doing_insert)
+ {
+ rl_end_undo_group ();
+ rl_do_undo ();
+ vi_doing_insert = 0;
+ }
+}
+
+rl_vi_replace ()
+{
+ int i;
+
+ vi_replace_count = 0;
+
+ vi_replace_map = rl_make_bare_keymap ();
+
+ for (i = ' '; i < 127; i++)
+ vi_replace_map[i].function = rl_vi_overstrike;
+
+ vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
+ vi_replace_map[CTRL('H')].function = rl_vi_overstrike_delete;
+ vi_replace_map[ESC].function = rl_vi_movement_mode;
+ vi_replace_map[RETURN].function = rl_newline;
+ vi_replace_map[NEWLINE].function = rl_newline;
+ keymap = vi_replace_map;
+}
diff --git a/gnu/usr.bin/gdb/regex.c b/gnu/usr.bin/gdb/regex.c
new file mode 100644
index 0000000..45c3478
--- /dev/null
+++ b/gnu/usr.bin/gdb/regex.c
@@ -0,0 +1,1738 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 1985, 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 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.
+
+
+ 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! */
+
+
+/* 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. */
+
+#ifdef emacs
+
+/* The `emacs' switch turns on certain special matching commands
+ that make sense only in emacs. */
+
+#include "config.h"
+#include "lisp.h"
+#include "buffer.h"
+#include "syntax.h"
+
+#else /* not emacs */
+
+#ifdef USG
+#ifndef BSTRING
+#define bcopy(s,d,n) memcpy((d),(s),(n))
+#define bcmp(s1,s2,n) memcmp((s1),(s2),(n))
+#define bzero(s,n) memset((s),0,(n))
+#endif
+#endif
+
+/* Make alloca work the best possible way. */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#ifdef sparc
+#include <alloca.h>
+#endif
+#endif
+
+/*
+ * Define the syntax stuff, so we can do the \<...\> things.
+ */
+
+#ifndef Sword /* must be non-zero in some of the tests below... */
+#define Sword 1
+#endif
+
+#define SYNTAX(c) re_syntax_table[c]
+
+#ifdef SYNTAX_TABLE
+
+char *re_syntax_table;
+
+#else
+
+static char re_syntax_table[256];
+
+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;
+
+ done = 1;
+}
+
+#endif /* SYNTAX_TABLE */
+#endif /* not emacs */
+
+#include "regex.h"
+
+/* 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 /* NFAILURES */
+
+/* width of a byte in bits */
+
+#define BYTEWIDTH 8
+
+#ifndef SIGN_EXTEND_CHAR
+#define SIGN_EXTEND_CHAR(x) (x)
+#endif
+
+static int obscure_syntax = 0;
+
+/* Specify the precise syntax of regexp for compilation.
+ This provides for compatibility for various utilities
+ which historically have different, incompatible syntaxes.
+
+ The argument SYNTAX is a bit-mask containing the two bits
+ RE_NO_BK_PARENS and RE_NO_BK_VBAR. */
+
+int
+re_set_syntax (syntax)
+{
+ int ret;
+
+ ret = obscure_syntax;
+ obscure_syntax = syntax;
+ return ret;
+}
+
+/* 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.
+*/
+
+#define PATPUSH(ch) (*b++ = (char) (ch))
+
+#define PATFETCH(c) \
+ {if (p == pend) goto end_of_pattern; \
+ c = * (unsigned char *) p++; \
+ if (translate) c = translate[c]; }
+
+#define PATFETCH_RAW(c) \
+ {if (p == pend) goto end_of_pattern; \
+ c = * (unsigned char *) p++; }
+
+#define PATUNFETCH p--
+
+#define EXTEND_BUFFER \
+ { char *old_buffer = bufp->buffer; \
+ if (bufp->allocated == (1<<16)) goto too_big; \
+ bufp->allocated *= 2; \
+ if (bufp->allocated > (1<<16)) bufp->allocated = (1<<16); \
+ if (!(bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated))) \
+ goto memory_exhausted; \
+ c = bufp->buffer - old_buffer; \
+ b += c; \
+ if (fixup_jump) \
+ fixup_jump += c; \
+ if (laststart) \
+ laststart += c; \
+ begalt += c; \
+ if (pending_exact) \
+ pending_exact += c; \
+ }
+
+static int store_jump (), insert_jump ();
+
+char *
+re_compile_pattern (pattern, size, bufp)
+ char *pattern;
+ int size;
+ struct re_pattern_buffer *bufp;
+{
+ register char *b = bufp->buffer;
+ register char *p = pattern;
+ char *pend = pattern + size;
+ register unsigned c, c1;
+ char *p1;
+ 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;
+
+ /* 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 = 28;
+ if (bufp->buffer)
+ /* EXTEND_BUFFER loses when bufp->allocated is 0 */
+ bufp->buffer = (char *) realloc (bufp->buffer, 28);
+ else
+ /* Caller did not allocate a buffer. Do it for him */
+ bufp->buffer = (char *) malloc (28);
+ if (!bufp->buffer) goto memory_exhausted;
+ begalt = b = bufp->buffer;
+ }
+
+ while (p != pend)
+ {
+ if (b - bufp->buffer > bufp->allocated - 10)
+ /* Note that EXTEND_BUFFER clobbers c */
+ EXTEND_BUFFER;
+
+ PATFETCH (c);
+
+ switch (c)
+ {
+ case '$':
+ if (obscure_syntax & RE_TIGHT_VBAR)
+ {
+ if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p != pend)
+ goto normal_char;
+ /* Make operand of last vbar end before this `$'. */
+ if (fixup_jump)
+ store_jump (fixup_jump, jump, b);
+ fixup_jump = 0;
+ PATPUSH (endline);
+ break;
+ }
+
+ /* $ means succeed if at end of line, but only in special contexts.
+ If randomly in the middle of a pattern, it is a normal character. */
+ if (p == pend || *p == '\n'
+ || (obscure_syntax & RE_CONTEXT_INDEP_OPS)
+ || (obscure_syntax & RE_NO_BK_PARENS
+ ? *p == ')'
+ : *p == '\\' && p[1] == ')')
+ || (obscure_syntax & RE_NO_BK_VBAR
+ ? *p == '|'
+ : *p == '\\' && p[1] == '|'))
+ {
+ PATPUSH (endline);
+ break;
+ }
+ goto normal_char;
+
+ case '^':
+ /* ^ means succeed if at beg of line, but only if no preceding pattern. */
+
+ if (laststart && 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;
+ PATPUSH (begline);
+ begalt = b;
+ }
+ else
+ PATPUSH (begline);
+ break;
+
+ case '+':
+ case '?':
+ if (obscure_syntax & RE_BK_PLUS_QM)
+ goto normal_char;
+ handle_plus:
+ case '*':
+ /* If there is no previous pattern, char not special. */
+ if (!laststart && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS))
+ goto normal_char;
+ /* If there is a sequence of repetition chars,
+ collapse it down to equivalent 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 0 matches is allowed,
+ and whether 2 or more matches is allowed. */
+ if (many_times_ok)
+ {
+ /* If more than one repetition is allowed,
+ put in a backward jump at the end. */
+ store_jump (b, maybe_finalize_jump, laststart - 3);
+ b += 3;
+ }
+ insert_jump (on_failure_jump, laststart, b + 3, b);
+ pending_exact = 0;
+ b += 3;
+ if (!zero_times_ok)
+ {
+ /* At least one repetition required: insert before the loop
+ a skip over the initial on-failure-jump instruction */
+ insert_jump (dummy_failure_jump, laststart, laststart + 6, b);
+ b += 3;
+ }
+ break;
+
+ case '.':
+ laststart = b;
+ PATPUSH (anychar);
+ break;
+
+ case '[':
+ while (b - bufp->buffer
+ > bufp->allocated - 3 - (1 << BYTEWIDTH) / BYTEWIDTH)
+ /* Note that EXTEND_BUFFER clobbers c */
+ EXTEND_BUFFER;
+
+ laststart = b;
+ if (*p == '^')
+ PATPUSH (charset_not), p++;
+ else
+ PATPUSH (charset);
+ p1 = p;
+
+ PATPUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+ /* Clear the whole map */
+ bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+ /* Read in characters and ranges, setting map bits */
+ while (1)
+ {
+ PATFETCH (c);
+ if (c == ']' && p != p1 + 1) break;
+ if (*p == '-' && p[1] != ']')
+ {
+ PATFETCH (c1);
+ PATFETCH (c1);
+ while (c <= c1)
+ b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH), c++;
+ }
+ else
+ {
+ b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH);
+ }
+ }
+ /* Discard any 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_NO_BK_VBAR))
+ goto normal_char;
+ else
+ goto handle_bar;
+
+ 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;
+ if (regnum < RE_NREGS)
+ {
+ PATPUSH (start_memory);
+ PATPUSH (regnum);
+ }
+ *stackp++ = b - bufp->buffer;
+ *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)
+ {
+ PATPUSH (stop_memory);
+ PATPUSH (stackp[-1]);
+ }
+ stackp -= 2;
+ fixup_jump = 0;
+ if (*stackp)
+ fixup_jump = *stackp + bufp->buffer - 1;
+ laststart = *--stackp + bufp->buffer;
+ break;
+
+ case '|':
+ if (obscure_syntax & RE_NO_BK_VBAR)
+ goto normal_backsl;
+ handle_bar:
+ insert_jump (on_failure_jump, begalt, b + 6, b);
+ pending_exact = 0;
+ b += 3;
+ if (fixup_jump)
+ store_jump (fixup_jump, jump, b);
+ fixup_jump = b;
+ b += 3;
+ laststart = 0;
+ begalt = b;
+ break;
+
+#ifdef emacs
+ case '=':
+ PATPUSH (at_dot);
+ break;
+
+ case 's':
+ laststart = b;
+ PATPUSH (syntaxspec);
+ PATFETCH (c);
+ PATPUSH (syntax_spec_code[c]);
+ break;
+
+ case 'S':
+ laststart = b;
+ PATPUSH (notsyntaxspec);
+ PATFETCH (c);
+ PATPUSH (syntax_spec_code[c]);
+ break;
+#endif /* emacs */
+
+ case 'w':
+ laststart = b;
+ PATPUSH (wordchar);
+ break;
+
+ case 'W':
+ laststart = b;
+ PATPUSH (notwordchar);
+ break;
+
+ case '<':
+ PATPUSH (wordbeg);
+ break;
+
+ case '>':
+ PATPUSH (wordend);
+ break;
+
+ case 'b':
+ PATPUSH (wordbound);
+ break;
+
+ case 'B':
+ PATPUSH (notwordbound);
+ break;
+
+ case '`':
+ PATPUSH (begbuf);
+ break;
+
+ case '\'':
+ PATPUSH (endbuf);
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ c1 = c - '0';
+ if (c1 >= regnum)
+ goto normal_char;
+ for (stackt = stackp - 2; stackt > stackb; stackt -= 4)
+ if (*stackt == c1)
+ goto normal_char;
+ laststart = b;
+ PATPUSH (duplicate);
+ PATPUSH (c1);
+ break;
+
+ case '+':
+ case '?':
+ if (obscure_syntax & RE_BK_PLUS_QM)
+ goto handle_plus;
+
+ 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:
+ 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 == '?')))
+ {
+ laststart = b;
+ PATPUSH (exactn);
+ pending_exact = b;
+ PATPUSH (0);
+ }
+ PATPUSH (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 where `from' points a jump operation to jump to where `to' points.
+ `opcode' is the opcode to store. */
+
+static int
+store_jump (from, opcode, to)
+ char *from, *to;
+ char opcode;
+{
+ from[0] = opcode;
+ from[1] = (to - (from + 3)) & 0377;
+ from[2] = (to - (from + 3)) >> 8;
+}
+
+/* Open up space at char FROM, and insert there a jump to TO.
+ CURRENT_END gives te end of the storage no 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 int
+insert_jump (op, from, to, current_end)
+ char op;
+ char *from, *to, *current_end;
+{
+ register char *pto = current_end + 3;
+ register char *pfrom = current_end;
+ while (pfrom != from)
+ *--pto = *--pfrom;
+ store_jump (from, op, to);
+}
+
+/* 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 char *stackb[NFAILURES];
+ unsigned char **stackp = stackb;
+
+ bzero (fastmap, (1 << BYTEWIDTH));
+ bufp->fastmap_accurate = 1;
+ bufp->can_be_null = 0;
+
+ while (p)
+ {
+ 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 finalize_jump:
+ case maybe_finalize_jump:
+ case jump:
+ case dummy_failure_jump:
+ bufp->can_be_null = 1;
+ j = *p++ & 0377;
+ j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p += j + 1; /* The 1 compensates for missing ++ above */
+ 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)
+ continue;
+ p++;
+ j = *p++ & 0377;
+ j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p += j + 1; /* The 1 compensates for missing ++ above */
+ if (stackp != stackb && *stackp == p)
+ stackp--;
+ continue;
+
+ case on_failure_jump:
+ j = *p++ & 0377;
+ j += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p++;
+ *++stackp = p + j;
+ 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)
+ return;
+ /* 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;
+#endif /* 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;
+ }
+
+ /* 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;
+ }
+}
+
+/* Like re_search_2, below, but only one string is specified. */
+
+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, 0, 0, string, size, startpos, range, regs, size);
+}
+
+/* Like re_match_2 but tries first a match starting 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, the starting positions tried are
+ STARTPOS, STARTPOS - 1, etc.
+ It is up to the caller to make sure that range is not so large
+ as to take the starting position outside of the input strings.
+
+The value returned is the position 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 = size1 + size2;
+ int val;
+
+ /* Update the fastmap now if not correct already */
+ if (fastmap && !pbufp->fastmap_accurate)
+ re_compile_fastmap (pbufp);
+
+ /* 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 && pbufp->can_be_null != 1)
+ {
+ if (range > 0)
+ {
+ 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]);
+
+ if (translate)
+ {
+ while (range > lim && !fastmap[translate[*p++]])
+ range--;
+ }
+ else
+ {
+ while (range > lim && !fastmap[*p++])
+ range--;
+ }
+ startpos += irange - range;
+ }
+ else
+ {
+ register unsigned char c;
+ if (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
+ && fastmap && pbufp->can_be_null == 0)
+ return -1;
+
+ val = re_match_2 (pbufp, string1, size1, string2, size2, startpos, regs, mstop);
+ if (0 <= val)
+ {
+ if (val == -2)
+ return -2;
+ return startpos;
+ }
+
+#ifdef C_ALLOCA
+ alloca (0);
+#endif /* C_ALLOCA */
+
+ advance:
+ if (!range) break;
+ 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, 0, 0, string, size, pos, regs, size);
+}
+#endif /* emacs */
+
+/* Maximum size of failure stack. Beyond this, overflow is an error. */
+
+int re_max_failures = 2000;
+
+static int bcmp_translate();
+/* Match the pattern described by PBUFP
+ against data which is the virtual concatenation of STRING1 and STRING2.
+ SIZE1 and SIZE2 are the sizes of the two data strings.
+ Start the match at position POS.
+ Do not consider matching past the position MSTOP.
+
+ 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, size1, string2, size2, pos, regs, mstop)
+ struct re_pattern_buffer *pbufp;
+ unsigned char *string1, *string2;
+ int size1, size2;
+ int pos;
+ struct re_registers *regs;
+ int mstop;
+{
+ register unsigned char *p = (unsigned char *) pbufp->buffer;
+ register unsigned char *pend = p + pbufp->used;
+ /* End of first string */
+ unsigned char *end1;
+ /* End of second string */
+ unsigned char *end2;
+ /* Pointer just past last char to consider matching */
+ unsigned char *end_match_1, *end_match_2;
+ register unsigned char *d, *dend;
+ register int mcnt;
+ unsigned char *translate = (unsigned char *) pbufp->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 two char *'s.
+ The first one pushed is where to resume scanning the pattern;
+ the second pushed is where to resume scanning the strings.
+ If the latter is zero, the failure point is a "dummy".
+ If a failure happens and the innermost failure point is dormant,
+ it discards that failure point and tries the next one. */
+
+ unsigned char *initial_stack[2 * NFAILURES];
+ unsigned char **stackb = initial_stack;
+ unsigned char **stackp = stackb, **stacke = &stackb[2 * NFAILURES];
+
+ /* Information on the "contents" of registers.
+ These are pointers into the input strings; they record
+ just what was matched (on this attempt) by some part of the pattern.
+ The start_memory command stores the start of a register's contents
+ and the stop_memory command stores the end.
+
+ At that point, regstart[regnum] points to the first character in the register,
+ regend[regnum] points to the first character beyond the end of the register,
+ regstart_seg1[regnum] is true iff regstart[regnum] points into string1,
+ and regend_seg1[regnum] is true iff regend[regnum] points into string1. */
+
+ unsigned char *regstart[RE_NREGS];
+ unsigned char *regend[RE_NREGS];
+ unsigned char regstart_seg1[RE_NREGS], regend_seg1[RE_NREGS];
+
+ /* Set up pointers to ends of strings.
+ Don't allow the second string to be empty unless both are empty. */
+ if (!size2)
+ {
+ 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;
+ }
+
+ /* Initialize \) text positions to -1
+ to mark ones that no \( or \) has been seen for. */
+
+ for (mcnt = 0; mcnt < sizeof (regend) / sizeof (*regend); mcnt++)
+ regend[mcnt] = (unsigned char *) -1;
+
+ /* `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 (pos <= size1)
+ d = string1 + pos, dend = end_match_1;
+ else
+ d = string2 + pos - size1, dend = end_match_2;
+
+/* Write PREFETCH; just before fetching a character with *d. */
+#define PREFETCH \
+ while (d == dend) \
+ { if (dend == end_match_2) goto fail; /* end of string2 => failure */ \
+ d = string2; /* end of string1 => advance to string2. */ \
+ dend = end_match_2; }
+
+ /* This loop 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)
+ {
+ if (p == pend)
+ /* End of pattern means we have succeeded! */
+ {
+ /* If caller wants register contents data back, convert it to indices */
+ if (regs)
+ {
+ regs->start[0] = pos;
+ if (dend == end_match_1)
+ regs->end[0] = d - string1;
+ else
+ regs->end[0] = d - string2 + size1;
+ for (mcnt = 1; mcnt < RE_NREGS; mcnt++)
+ {
+ if (regend[mcnt] == (unsigned char *) -1)
+ {
+ regs->start[mcnt] = -1;
+ regs->end[mcnt] = -1;
+ continue;
+ }
+ if (regstart_seg1[mcnt])
+ regs->start[mcnt] = regstart[mcnt] - string1;
+ else
+ regs->start[mcnt] = regstart[mcnt] - string2 + size1;
+ if (regend_seg1[mcnt])
+ regs->end[mcnt] = regend[mcnt] - string1;
+ else
+ regs->end[mcnt] = regend[mcnt] - string2 + size1;
+ }
+ }
+ if (dend == end_match_1)
+ return (d - string1 - pos);
+ else
+ return d - string2 + size1 - pos;
+ }
+
+ /* Otherwise match next pattern command */
+#ifdef SWITCH_ENUM_BUG
+ switch ((int) ((enum regexpcode) *p++))
+#else
+ switch ((enum regexpcode) *p++)
+#endif
+ {
+
+ /* \( is represented by a start_memory, \) by a stop_memory.
+ Both of those commands contain a "register number" argument.
+ The text matched within the \( and \) is recorded under that number.
+ Then, \<digit> turns into a `duplicate' command which
+ is followed by the numeric value of <digit> as the register number. */
+
+ case start_memory:
+ regstart[*p] = d;
+ regstart_seg1[*p++] = (dend == end_match_1);
+ break;
+
+ case stop_memory:
+ regend[*p] = d;
+ regend_seg1[*p++] = (dend == end_match_1);
+ break;
+
+ case duplicate:
+ {
+ int regno = *p++; /* Get which register to match against */
+ register unsigned char *d2, *dend2;
+
+ d2 = regstart[regno];
+ dend2 = ((regstart_seg1[regno] == regend_seg1[regno])
+ ? regend[regno] : end_match_1);
+ while (1)
+ {
+ /* Advance to next segment in register contents, if necessary */
+ 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;
+
+ /* Advance to next segment in data being matched, if necessary */
+ PREFETCH;
+
+ /* mcnt gets # consecutive chars to compare */
+ mcnt = dend - d;
+ if (mcnt > dend2 - d2)
+ mcnt = dend2 - d2;
+ /* Compare that many; failure if mismatch, else skip them. */
+ if (translate ? bcmp_translate (d, d2, mcnt, translate) : bcmp (d, d2, mcnt))
+ goto fail;
+ d += mcnt, d2 += mcnt;
+ }
+ }
+ break;
+
+ case anychar:
+ /* fetch a data character */
+ PREFETCH;
+ /* Match anything but a newline. */
+ if ((translate ? translate[*d++] : *d++) == '\n')
+ goto fail;
+ break;
+
+ case charset:
+ case charset_not:
+ {
+ /* Nonzero for charset_not */
+ int not = 0;
+ register int c;
+ if (*(p - 1) == (unsigned char) charset_not)
+ not = 1;
+
+ /* fetch a data character */
+ PREFETCH;
+
+ 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;
+ d++;
+ break;
+ }
+
+ case begline:
+ if (d == string1 || d[-1] == '\n')
+ break;
+ 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:
+ if (stackp == stacke)
+ {
+ unsigned char **stackx;
+ if (stacke - stackb > re_max_failures * 2)
+ return -2;
+ stackx = (unsigned char **) alloca (2 * (stacke - stackb)
+ * sizeof (char *));
+ bcopy (stackb, stackx, (stacke - stackb) * sizeof (char *));
+ stackp = stackx + (stackp - stackb);
+ stacke = stackx + 2 * (stacke - stackb);
+ stackb = stackx;
+ }
+ mcnt = *p++ & 0377;
+ mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p++;
+ *stackp++ = mcnt + p;
+ *stackp++ = d;
+ break;
+
+ /* The end of a smart repeat has an maybe_finalize_jump back.
+ Change it either to a finalize_jump or an ordinary jump. */
+
+ case maybe_finalize_jump:
+ mcnt = *p++ & 0377;
+ mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p++;
+ {
+ register unsigned char *p2 = p;
+ /* Compare what follows with the begining of the repeat.
+ If we can establish that there is nothing that they would
+ both match, we can change to finalize_jump */
+ while (p2 != pend
+ && (*p2 == (unsigned char) stop_memory
+ || *p2 == (unsigned char) start_memory))
+ p2++;
+ 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;
+ if (p[-1] != (unsigned char) finalize_jump)
+ {
+ p[-1] = (unsigned char) jump;
+ goto nofinalize;
+ }
+
+ /* The end of a stupid repeat has a finalize-jump
+ back to the start, where another failure point will be made
+ which will point after all the repetitions found so far. */
+
+ case finalize_jump:
+ stackp -= 2;
+
+ case jump:
+ nofinalize:
+ mcnt = *p++ & 0377;
+ mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8;
+ p += mcnt + 1; /* The 1 compensates for missing ++ above */
+ break;
+
+ case dummy_failure_jump:
+ if (stackp == stacke)
+ {
+ unsigned char **stackx
+ = (unsigned char **) alloca (2 * (stacke - stackb)
+ * sizeof (char *));
+ bcopy (stackb, stackx, (stacke - stackb) * sizeof (char *));
+ stackp = stackx + (stackp - stackb);
+ stacke = stackx + 2 * (stacke - stackb);
+ stackb = stackx;
+ }
+ *stackp++ = 0;
+ *stackp++ = 0;
+ goto nofinalize;
+
+ case wordbound:
+ if (d == string1 /* Points to first char */
+ || d == end2 /* Points to end */
+ || (d == end1 && size2 == 0)) /* Points to end */
+ break;
+ if ((SYNTAX (d[-1]) == Sword)
+ != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
+ break;
+ goto fail;
+
+ case notwordbound:
+ if (d == string1 /* Points to first char */
+ || d == end2 /* Points to end */
+ || (d == end1 && size2 == 0)) /* Points to end */
+ goto fail;
+ if ((SYNTAX (d[-1]) == Sword)
+ != (SYNTAX (d == end1 ? *string2 : *d) == Sword))
+ goto fail;
+ break;
+
+ case wordbeg:
+ if (d == end2 /* Points to end */
+ || (d == end1 && size2 == 0) /* Points to end */
+ || SYNTAX (* (d == end1 ? string2 : d)) != Sword) /* Next char not a letter */
+ goto fail;
+ if (d == string1 /* Points to first char */
+ || SYNTAX (d[-1]) != Sword) /* prev char not letter */
+ break;
+ goto fail;
+
+ case wordend:
+ if (d == string1 /* Points to first char */
+ || SYNTAX (d[-1]) != Sword) /* prev char not letter */
+ goto fail;
+ if (d == end2 /* Points to end */
+ || (d == end1 && size2 == 0) /* Points to end */
+ || SYNTAX (d == end1 ? *string2 : *d) != Sword) /* Next char not a letter */
+ break;
+ goto fail;
+
+#ifdef emacs
+ case before_dot:
+ if (((d - string2 <= (unsigned) size2)
+ ? d - bf_p2 : d - bf_p1)
+ <= point)
+ goto fail;
+ break;
+
+ case at_dot:
+ if (((d - string2 <= (unsigned) size2)
+ ? d - bf_p2 : d - bf_p1)
+ == point)
+ goto fail;
+ break;
+
+ case after_dot:
+ if (((d - string2 <= (unsigned) size2)
+ ? d - bf_p2 : d - bf_p1)
+ >= 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;
+ break;
+
+ case notwordchar:
+ mcnt = (int) Sword;
+ goto matchnotsyntax;
+
+ case notsyntaxspec:
+ mcnt = *p++;
+ matchnotsyntax:
+ PREFETCH;
+ if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail;
+ break;
+#else
+ case wordchar:
+ PREFETCH;
+ if (SYNTAX (*d++) == 0) goto fail;
+ break;
+
+ case notwordchar:
+ PREFETCH;
+ if (SYNTAX (*d++) != 0) goto fail;
+ break;
+#endif /* not emacs */
+
+ case begbuf:
+ if (d == string1) /* Note, d cannot equal string2 */
+ break; /* unless string1 == string2. */
+ goto fail;
+
+ case endbuf:
+ if (d == end2 || (d == end1 && size2 == 0))
+ break;
+ goto fail;
+
+ case exactn:
+ /* Match the next few pattern characters exactly.
+ mcnt is how many characters to match. */
+ mcnt = *p++;
+ if (translate)
+ {
+ do
+ {
+ PREFETCH;
+ if (translate[*d++] != *p++) goto fail;
+ }
+ while (--mcnt);
+ }
+ else
+ {
+ do
+ {
+ PREFETCH;
+ if (*d++ != *p++) goto fail;
+ }
+ while (--mcnt);
+ }
+ break;
+ }
+ continue; /* Successfully matched one pattern command; keep matching */
+
+ /* Jump here if any matching operation fails. */
+ fail:
+ if (stackp != stackb)
+ /* A restart point is known. Restart there and pop it. */
+ {
+ if (!stackp[-2])
+ { /* If innermost failure point is dormant, flush it and keep looking */
+ stackp -= 2;
+ goto fail;
+ }
+ d = *--stackp;
+ p = *--stackp;
+ if (d >= string1 && d <= end1)
+ dend = end_match_1;
+ }
+ else break; /* Matching at this starting point really fails! */
+ }
+ return -1; /* Failure to match */
+}
+
+static int
+bcmp_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 bsd4.2 regex library */
+
+#ifndef emacs
+
+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, 0);
+}
+
+#endif /* emacs */
+
+#ifdef test
+
+#include <stdio.h>
+
+/* Indexed by a character, gives the upper case equivalent of the character */
+
+static 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
+ };
+
+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 = atoi (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);
+ }
+}
+
+#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
+
+printchar (c)
+ char c;
+{
+ if (c < 041 || 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/gdb/regex.h b/gnu/usr.bin/gdb/regex.h
new file mode 100644
index 0000000..d0d8a82
--- /dev/null
+++ b/gnu/usr.bin/gdb/regex.h
@@ -0,0 +1,185 @@
+/* Definitions for data structures callers pass the regex library.
+ Copyright (C) 1985, 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 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.
+
+
+ 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! */
+
+
+/* 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
+
+/* These bits are used in the obscure_syntax variable to choose among
+ alternative regexp syntaxes. */
+
+/* 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 1
+
+/* 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 2
+
+/* 0 means plain + or ? serves as an operator, and \+, \? are literals.
+ 1 means \+, \? are operators and plain +, ? are literals. */
+#define RE_BK_PLUS_QM 4
+
+/* 1 means | binds tighter than ^ or $.
+ 0 means the contrary. */
+#define RE_TIGHT_VBAR 8
+
+/* 1 means treat \n as an _OR operator
+ 0 means treat it as a normal character */
+#define RE_NEWLINE_OR 16
+
+/* 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 32
+
+/* Now define combinations of bits for the standard possibilities. */
+#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
+
+/* This data structure is used to represent a compiled pattern. */
+
+struct re_pattern_buffer
+ {
+ char *buffer; /* Space holding the compiled pattern commands. */
+ int allocated; /* Size of space that buffer points to */
+ int 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 quickly 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. */
+ };
+
+/* 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.
+
+ start[i] and end[i] record the string matched by \( ... \) grouping i,
+ for i from 1 to RE_NREGS - 1.
+ start[0] and end[0] record the entire string matched. */
+
+struct re_registers
+ {
+ int start[RE_NREGS];
+ int end[RE_NREGS];
+ };
+
+/* 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 whatever for its arguments.
+ Zero-bytes may appear in the compiled regular expression. */
+
+enum regexpcode
+ {
+ unused,
+ exactn, /* followed by one byte giving n, and then by n literal bytes */
+ begline, /* fails unless at beginning of line */
+ endline, /* fails 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. */
+ anychar, /* matches any one character */
+ charset, /* matches any one char belonging to specified set.
+ First following byte is # bitmap bytes.
+ Then come bytes for a bit-map 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, /* similar but match any character that is NOT one of those specified */
+ start_memory, /* starts remembering the text that is matched
+ and stores it in a memory register.
+ followed by one byte containing the register number.
+ Register numbers must be in the range 0 through NREGS. */
+ stop_memory, /* stops remembering the text that is matched
+ and stores it in a memory register.
+ followed by one byte containing the register number.
+ Register numbers must be in the range 0 through NREGS. */
+ duplicate, /* match a duplicate of something remembered.
+ Followed by one byte containing the index of the memory register. */
+ before_dot, /* Succeeds if before dot */
+ at_dot, /* Succeeds if at dot */
+ after_dot, /* Succeeds if after dot */
+ 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, Sword or such like */
+ notsyntaxspec /* Matches any character whose syntax differs from the specified. */
+ };
+
+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 ();
+
+/* 4.2 bsd compatibility (yuck) */
+extern char *re_comp ();
+extern int re_exec ();
+
+#ifdef SYNTAX_TABLE
+extern char *re_syntax_table;
+#endif
diff --git a/gnu/usr.bin/gdb/remote-sl.c b/gnu/usr.bin/gdb/remote-sl.c
new file mode 100644
index 0000000..4c72197
--- /dev/null
+++ b/gnu/usr.bin/gdb/remote-sl.c
@@ -0,0 +1,10 @@
+/*
+ * The binary remote protocol is still under development at LBL;
+ * the current version can't be released.
+ * Sorry, folks...
+ */
+int
+sl_open()
+{
+ return -1;
+}
diff --git a/gnu/usr.bin/gdb/remote.c b/gnu/usr.bin/gdb/remote.c
new file mode 100644
index 0000000..59658a8
--- /dev/null
+++ b/gnu/usr.bin/gdb/remote.c
@@ -0,0 +1,626 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson and Steven McCanne of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Header: /home/cvs/386BSD/src/usr.bin/gdb/remote.c,v 1.1.1.1 1993/06/12 14:52:22 rgrimes Exp $;
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)remote.c 6.5 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+#include "param.h"
+
+#include <stdio.h>
+#include <varargs.h>
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "wait.h"
+
+#include "kgdb_proto.h"
+
+static FILE *kiodebug;
+static int icache = 1;
+extern int kernel_debugging;
+
+static int remote_cache_valid;
+static int remote_instub;
+
+static void remote_signal();
+static void remote_debug();
+static void print_msg();
+
+static int remote_mtu;
+static int (*send_msg)();
+static int (*recv_msg)();
+static void (*closelink)();
+
+static u_char *inbuffer;
+static u_char *outbuffer;
+
+/*
+ * Statistics.
+ */
+static int remote_ierrs;
+static int remote_oerrs;
+static int remote_seqerrs;
+static int remote_spurious;
+
+#define PUTCMD(cmd) m_xchg(cmd, (u_char *)0, 0, (u_char *)0, (int *)0)
+
+/*
+ * Send an outbound message to the remote machine and read the reply.
+ * Either or both message buffers may be NULL.
+ */
+static int
+m_xchg(type, out, outlen, in, inlen)
+ int type;
+ u_char *out;
+ int outlen;
+ u_char *in;
+ int *inlen;
+{
+ register int err, (*send)() = send_msg, (*recv)() = recv_msg;
+ int ack;
+ static int seqbit = 0;
+
+ if (!remote_instub) {
+ remote_instub = 1;
+ PUTCMD(KGDB_EXEC);
+ }
+
+ seqbit ^= KGDB_SEQ;
+ while (1) {
+ err = (*send)(type | seqbit, out, outlen);
+ if (err) {
+ ++remote_oerrs;
+ if (kiodebug)
+ remote_debug("send error %d\n", err);
+ }
+ if (kiodebug)
+ print_msg(type | seqbit, out, outlen, 'O');
+
+ recv:
+ err = (*recv)(&ack, in, inlen);
+ if (err) {
+ ++remote_ierrs;
+ if (kiodebug)
+ remote_debug("recv error %d\n", err);
+ remote_cache_valid = 0;
+ } else if (kiodebug)
+ print_msg(ack, in, inlen ? *inlen : 0, 'I');
+
+ if (err)
+ continue;
+
+ if ((ack & KGDB_ACK) == 0 || KGDB_CMD(ack) != KGDB_CMD(type)) {
+ ++remote_spurious;
+ continue;
+ }
+ if ((ack & KGDB_SEQ) ^ seqbit) {
+ ++remote_seqerrs;
+ goto recv;
+ }
+ return ack;
+ }
+}
+
+/*
+ * Wait for the specified message type. Discard anything else.
+ * (this is used by 'remote-signal' to help us resync with other side.)
+ */
+static void
+m_recv(type, in, inlen)
+ int type;
+ u_char *in;
+ int *inlen;
+{
+ int reply, err;
+
+ while (1) {
+ err = (*recv_msg)(&reply, in, inlen);
+ if (err) {
+ ++remote_ierrs;
+ if (kiodebug)
+ remote_debug("recv error %d\n", err);
+ } else if (kiodebug)
+ print_msg(reply, in, inlen ? *inlen : 0, 'I');
+
+ if (KGDB_CMD(reply) == type)
+ return;
+ ++remote_spurious;
+ }
+}
+
+/*
+ * Send a message. Do not wait for *any* response from the other side.
+ * Some other thread of control will pick up the ack that will be generated.
+ */
+static void
+m_send(type, buf, len)
+ int type;
+ u_char *buf;
+ int len;
+{
+ int err;
+
+ if (!remote_instub) {
+ remote_instub = 1;
+ PUTCMD(KGDB_EXEC);
+ }
+
+ err = (*send_msg)(type, buf, len);
+ if (err) {
+ ++remote_ierrs;
+ if (kiodebug)
+ remote_debug("[send error %d] ", err);
+ }
+ if (kiodebug)
+ print_msg(type, buf, len, 'O');
+}
+
+/*
+ * Open a connection to a remote debugger.
+ * NAME is the filename used for communication.
+ */
+void
+remote_open(name, from_tty)
+ char *name;
+ int from_tty;
+{
+ int bufsize;
+
+ remote_debugging = 0;
+ if (sl_open(name, &send_msg, &recv_msg, &closelink, &remote_mtu,
+ &bufsize))
+ return;
+ if (from_tty)
+ printf("Remote debugging using %s\n", name);
+ remote_debugging = 1;
+
+ remote_cache_valid = 0;
+
+ inbuffer = (u_char *)malloc(bufsize);
+ outbuffer = (u_char *)malloc(bufsize);
+
+ remote_signal();
+
+ remote_ierrs = 0;
+ remote_oerrs = 0;
+ remote_spurious = 0;
+}
+
+/*
+ * Close the open connection to the remote debugger. Use this when you want
+ * to detach and do something else with your gdb.
+ */
+void
+remote_close(from_tty)
+ int from_tty;
+{
+ if (!remote_debugging)
+ error("remote debugging not enabled");
+
+ remote_debugging = 0;
+ /*
+ * Take remote machine out of debug mode.
+ */
+ (void)PUTCMD(KGDB_KILL);
+ (*closelink)();
+ if (from_tty)
+ printf("Ending remote debugging\n");
+
+ free((char *)inbuffer);
+ free((char *)outbuffer);
+}
+
+/*
+ * Tell the remote machine to resume.
+ */
+int
+remote_resume(step, signal)
+ int step, signal;
+{
+ if (!step) {
+ (void)PUTCMD(KGDB_CONT);
+ remote_instub = 0;
+ } else {
+#ifdef NO_SINGLE_STEP
+ single_step(0);
+#else
+ (void)PUTCMD(KGDB_STEP);
+#endif
+ }
+}
+
+/*
+ * Wait until the remote machine stops, then return, storing status in STATUS
+ * just as `wait' would.
+ */
+int
+remote_wait(status)
+ WAITTYPE *status;
+{
+ int len;
+
+ WSETEXIT((*status), 0);
+ /*
+ * When the machine stops, it will send us a KGDB_SIGNAL message,
+ * so we wait for one of these.
+ */
+ m_recv(KGDB_SIGNAL, inbuffer, &len);
+ WSETSTOP((*status), inbuffer[0]);
+}
+
+/*
+ * Register context as of last remote_fetch_registers().
+ */
+static char reg_cache[REGISTER_BYTES];
+
+/*
+ * Read the remote registers into the block REGS.
+ */
+void
+remote_fetch_registers(regs)
+ char *regs;
+{
+ int regno, len, rlen, ack;
+ u_char *cp, *ep;
+
+ regno = -1;
+ do {
+ outbuffer[0] = regno + 1;
+ ack = m_xchg(remote_cache_valid ?
+ KGDB_REG_R|KGDB_DELTA : KGDB_REG_R,
+ outbuffer, 1, inbuffer, &len);
+ cp = inbuffer;
+ ep = cp + len;
+ while (cp < ep) {
+ regno = *cp++;
+ rlen = REGISTER_RAW_SIZE(regno);
+ bcopy((char *)cp,
+ &reg_cache[REGISTER_BYTE(regno)], rlen);
+ cp += rlen;
+ }
+ } while (ack & KGDB_MORE);
+
+ remote_cache_valid = 1;
+ bcopy(reg_cache, regs, REGISTER_BYTES);
+}
+
+/*
+ * Store the remote registers from the contents of the block REGS.
+ */
+void
+remote_store_registers(regs)
+ char *regs;
+{
+ u_char *cp, *ep;
+ int regno, off, rlen;
+
+ cp = outbuffer;
+ ep = cp + remote_mtu;
+
+ for (regno = 0; regno < NUM_REGS; ++regno) {
+ off = REGISTER_BYTE(regno);
+ rlen = REGISTER_RAW_SIZE(regno);
+ if (!remote_cache_valid ||
+ bcmp(&regs[off], &reg_cache[off], rlen) != 0) {
+ if (cp + rlen + 1 >= ep) {
+ (void)m_xchg(KGDB_REG_W,
+ outbuffer, cp - outbuffer,
+ (u_char *)0, (int *)0);
+ cp = outbuffer;
+ }
+ *cp++ = regno;
+ bcopy(&regs[off], cp, rlen);
+ cp += rlen;
+ }
+ }
+ if (cp != outbuffer)
+ (void)m_xchg(KGDB_REG_W, outbuffer, cp - outbuffer,
+ (u_char *)0, (int *)0);
+ bcopy(regs, reg_cache, REGISTER_BYTES);
+}
+
+/*
+ * Store a chunk of memory into the remote host.
+ * 'remote_addr' is the address in the remote memory space.
+ * 'cp' is the address of the buffer in our space, and 'len' is
+ * the number of bytes. Returns an errno status.
+ */
+int
+remote_write_inferior_memory(remote_addr, cp, len)
+ CORE_ADDR remote_addr;
+ u_char *cp;
+ int len;
+{
+ int cnt;
+
+ while (len > 0) {
+ cnt = min(len, remote_mtu - 4);
+ bcopy((char *)&remote_addr, outbuffer, 4);
+ bcopy(cp, outbuffer + 4, cnt);
+ (void)m_xchg(KGDB_MEM_W, outbuffer, cnt + 4, inbuffer, &len);
+
+ if (inbuffer[0])
+ return inbuffer[0];
+
+ remote_addr += cnt;
+ cp += cnt;
+ len -= cnt;
+ }
+ return 0;
+}
+
+/*
+ * Read memory data directly from the remote machine.
+ * 'remote_addr' is the address in the remote memory space.
+ * 'cp' is the address of the buffer in our space, and 'len' is
+ * the number of bytes. Returns an errno status.
+ */
+static int
+remote_read_memory(remote_addr, cp, len)
+ CORE_ADDR remote_addr;
+ u_char *cp;
+ int len;
+{
+ int cnt, inlen;
+
+ while (len > 0) {
+ cnt = min(len, remote_mtu - 1);
+ outbuffer[0] = cnt;
+ bcopy((char *)&remote_addr, (char *)&outbuffer[1], 4);
+
+ (void)m_xchg(KGDB_MEM_R, outbuffer, 5, inbuffer, &inlen);
+
+ if (inbuffer[0] != 0)
+ return inbuffer[0];
+
+ if (cnt != inlen - 1)
+ /* XXX */
+ error("remote_read_memory() request botched");
+
+ bcopy((char *)&inbuffer[1], (char *)cp, cnt);
+
+ remote_addr += cnt;
+ cp += cnt;
+ len -= cnt;
+ }
+ return 0;
+}
+
+int
+remote_read_inferior_memory(remote_addr, cp, len)
+ CORE_ADDR remote_addr;
+ char *cp;
+ int len;
+{
+ int stat = 0;
+
+ if (icache) {
+ extern CORE_ADDR text_start, text_end;
+ CORE_ADDR xferend = remote_addr + len;
+
+ if (remote_addr < text_end && text_start < xferend) {
+ /*
+ * at least part of this xfer is in the text
+ * space -- xfer the overlap from the exec file.
+ */
+ if (remote_addr >= text_start && xferend < text_end)
+ return (xfer_core_file(remote_addr, cp, len));
+ if (remote_addr >= text_start) {
+ int i = text_end - remote_addr;
+
+ if (stat = xfer_core_file(remote_addr, cp, i))
+ return (stat);
+ remote_addr += i;
+ cp += i;
+ len -= i;
+ } else if (xferend <= text_end) {
+ int i = xferend - text_start;
+
+ len = text_start - remote_addr;
+ if (stat = xfer_core_file(text_start,
+ cp + len, i))
+ return (stat);
+ }
+ }
+ }
+ return remote_read_memory(remote_addr, cp, len);
+}
+
+/*
+ * Signal the remote machine. The remote end might be idle or it might
+ * already be in debug mode -- we need to handle both case. Thus, we use
+ * the framing character as the wakeup byte, and send a SIGNAL packet.
+ * If the remote host is idle, the framing character will wake it up.
+ * If it is in the kgdb stub, then we will get a SIGNAL reply.
+ */
+static void
+remote_signal()
+{
+ if (!remote_debugging)
+ printf("Remote debugging not enabled.\n");
+ else {
+ remote_instub = 0;
+ m_send(KGDB_SIGNAL, (u_char *)0, 0);
+ }
+}
+
+static void
+remote_signal_command()
+{
+ extern int stop_after_attach;
+
+ if (!remote_debugging)
+ error("Not debugging remote.");
+ remote_cache_valid = 0;
+ remote_signal();
+ restart_remote();
+}
+
+/*
+ * Print a message for debugging.
+ */
+static void
+print_msg(type, buf, len, dir)
+ int type;
+ u_char *buf;
+ int len;
+ int dir;
+{
+ int i;
+ char *s;
+
+ switch (KGDB_CMD(type)) {
+ case KGDB_MEM_R: s = "memr"; break;
+ case KGDB_MEM_W: s = "memw"; break;
+ case KGDB_REG_R: s = "regr"; break;
+ case KGDB_REG_W: s = "regw"; break;
+ case KGDB_CONT: s = "cont"; break;
+ case KGDB_STEP: s = "step"; break;
+ case KGDB_KILL: s = "kill"; break;
+ case KGDB_SIGNAL: s = "sig "; break;
+ case KGDB_EXEC: s = "exec"; break;
+ default: s = "unk "; break;
+ }
+ remote_debug("%c %c%c%c%c %s (%02x): ", dir,
+ (type & KGDB_ACK) ? 'A' : '.',
+ (type & KGDB_DELTA) ? 'D' : '.',
+ (type & KGDB_MORE) ? 'M' : '.',
+ (type & KGDB_SEQ) ? '-' : '+',
+ s, type);
+ if (buf)
+ for (i = 0; i < len; ++i)
+ remote_debug("%02x", buf[i]);
+ remote_debug("\n");
+}
+
+static void
+set_remote_text_refs_command(arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ icache = !parse_binary_operation("set remote-text-refs", arg);
+}
+
+static void
+remote_debug_command(arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ char *name;
+
+ if (kiodebug != 0 && kiodebug != stderr)
+ (void)fclose(kiodebug);
+
+ if (arg == 0) {
+ kiodebug = 0;
+ printf("Remote debugging off.\n");
+ return;
+ }
+ if (arg[0] == '-') {
+ kiodebug = stderr;
+ name = "stderr";
+ } else {
+ kiodebug = fopen(arg, "w");
+ if (kiodebug == 0) {
+ printf("Cannot open '%s'.\n", arg);
+ return;
+ }
+ name = arg;
+ }
+ printf("Remote debugging output routed to %s.\n", name);
+}
+
+/* ARGSUSED */
+static void
+remote_info(arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ printf("Using %s for text references.\n",
+ icache? "local executable" : "remote");
+ printf("Protocol debugging is %s.\n", kiodebug? "on" : "off");
+ printf("%d spurious input messages.\n", remote_spurious);
+ printf("%d input errors; %d output errors; %d sequence errors.\n",
+ remote_ierrs, remote_oerrs, remote_seqerrs);
+}
+
+/* VARARGS */
+static void
+remote_debug(va_alist)
+ va_dcl
+{
+ register char *cp;
+ va_list ap;
+
+ va_start(ap);
+ cp = va_arg(ap, char *);
+ (void)vfprintf(kiodebug, cp, ap);
+ va_end(ap);
+ fflush(kiodebug);
+}
+
+extern struct cmd_list_element *setlist;
+
+void
+_initialize_remote()
+{
+ add_com("remote-signal", class_run, remote_signal_command,
+ "If remote debugging, send interrupt signal to remote.");
+ add_cmd("remote-text-refs", class_support,
+ set_remote_text_refs_command,
+"Enable/disable use of local executable for text segment references.\n\
+If on, all memory read/writes go to remote.\n\
+If off, text segment reads use the local executable.",
+ &setlist);
+
+ add_com("remote-debug", class_run, remote_debug_command,
+"With a file name argument, enables output of remote protocol debugging\n\
+messages to said file. If file is `-', stderr is used.\n\
+With no argument, remote debugging is disabled.");
+
+ add_info("remote", remote_info,
+ "Show current settings of remote debugging options.");
+}
+
diff --git a/gnu/usr.bin/gdb/source.c b/gnu/usr.bin/gdb/source.c
new file mode 100644
index 0000000..bb65e1c
--- /dev/null
+++ b/gnu/usr.bin/gdb/source.c
@@ -0,0 +1,1166 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)source.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* List lines of source files for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987, 1988, 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. */
+
+#include <stdio.h>
+#include <string.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+
+#ifdef USG
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
+/* Path of directories to search for source files.
+ Same format as the PATH environment variable's value. */
+
+static 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;
+
+/* 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;
+
+
+struct symtab *psymtab_to_symtab ();
+
+/* Set the source file default for the "list" command, specifying a
+ symtab. Sigh. Behaivior specification: If it is called with a
+ non-zero argument, that is the symtab to select. If it is not,
+ first lookup "main"; if it exists, use the symtab and line it
+ defines. If not, take the last symtab in the symtab_list (if it
+ exists) or the last symtab in the psytab_list (if *it* exists). If
+ none of this works, report an error. */
+
+void
+select_source_symtab (s)
+ register struct symtab *s;
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct partial_symtab *ps, *cs_pst;
+
+ if (s)
+ {
+ current_source_symtab = s;
+ current_source_line = 1;
+ return;
+ }
+
+ /* Make the default place to list be the function `main'
+ if one exists. */
+ if (lookup_symbol ("main", 0, VAR_NAMESPACE, 0))
+ {
+ sals = decode_line_spec ("main", 1);
+ sal = sals.sals[0];
+ free (sals.sals);
+ current_source_symtab = sal.symtab;
+ current_source_line = max (sal.line - 9, 1);
+ return;
+ }
+
+ /* All right; find the last file in the symtab list (ignoring .h's). */
+
+ if (s = symtab_list)
+ {
+ do
+ {
+ char *name = s->filename;
+ int len = strlen (name);
+ if (! (len > 2 && !strcmp (&name[len - 2], ".h")))
+ current_source_symtab = s;
+ s = s->next;
+ }
+ while (s);
+ current_source_line = 1;
+ }
+ else if (partial_symtab_list)
+ {
+ ps = partial_symtab_list;
+ while (ps)
+ {
+ char *name = ps->filename;
+ int len = strlen (name);
+ if (! (len > 2 && !strcmp (&name[len - 2], ".h")))
+ cs_pst = ps;
+ ps = ps->next;
+ }
+ 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);
+ else
+ current_source_symtab = 0;
+ current_source_line = 1;
+ }
+}
+
+static void
+directories_info ()
+{
+ printf ("Source directories searched: %s\n", source_path);
+}
+
+void
+init_source_path ()
+{
+ register struct symtab *s;
+
+ source_path = savestring (current_directory, strlen (current_directory));
+
+ /* Forget what we learned about line positions in source files;
+ must check again now since files may be found in
+ a different directory now. */
+ for (s = symtab_list; s; s = s->next)
+ if (s->line_charpos != 0)
+ {
+ free (s->line_charpos);
+ s->line_charpos = 0;
+ }
+}
+
+void
+directory_command (dirname, from_tty)
+ char *dirname;
+ int from_tty;
+{
+ char *old = source_path;
+
+ dont_repeat ();
+
+ if (dirname == 0)
+ {
+ if (query ("Reinitialize source path to %s? ", current_directory))
+ {
+ init_source_path ();
+ free (old);
+ }
+ }
+ else
+ {
+ dirname = tilde_expand (dirname);
+ make_cleanup (free, dirname);
+
+ do
+ {
+ char *name = dirname;
+ register char *p;
+ struct stat st;
+
+ {
+ char *colon = index (name, ':');
+ char *space = index (name, ' ');
+ char *tab = index (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 == ' ' || *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 != '/')
+ name = concat (current_directory, "/", name);
+ else
+ name = savestring (name, p - name);
+ make_cleanup (free, name);
+
+ if (stat (name, &st) < 0)
+ perror_with_name (name);
+ if ((st.st_mode & S_IFMT) != S_IFDIR)
+ error ("%s is not a directory.", name);
+
+ append:
+ {
+ register unsigned int len = strlen (name);
+
+ p = source_path;
+ while (1)
+ {
+ if (!strncmp (p, name, len)
+ && (p[len] == '\0' || p[len] == ':'))
+ {
+ if (from_tty)
+ printf ("\"%s\" is already in the source path.\n", name);
+ break;
+ }
+ p = index (p, ':');
+ if (p != 0)
+ ++p;
+ else
+ break;
+ }
+ if (p == 0)
+ {
+ source_path = concat (old, ":", name);
+ free (old);
+ old = source_path;
+ }
+ }
+ } while (*dirname != '\0');
+ if (from_tty)
+ directories_info ();
+ }
+}
+
+/* Open a file named STRING, searching path PATH (dir names sep by colons)
+ 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 ".")
+ 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 "/"
+
+ 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;
+
+ if (!path)
+ path = ".";
+
+ /* ./foo => foo */
+ while (string[0] == '.' && string[1] == '/')
+ string += 2;
+
+ if (try_cwd_first || string[0] == '/')
+ {
+ filename = string;
+ fd = open (filename, mode, prot);
+ if (fd >= 0 || string[0] == '/')
+ goto done;
+ }
+
+ filename = (char *) alloca (strlen (path) + strlen (string) + 2);
+ fd = -1;
+ for (p = path; p; p = p1 ? p1 + 1 : 0)
+ {
+ p1 = (char *) index (p, ':');
+ if (p1)
+ len = p1 - p;
+ else
+ len = strlen (p);
+
+ strncpy (filename, p, len);
+ filename[len] = 0;
+ strcat (filename, "/");
+ strcat (filename, string);
+
+ fd = open (filename, mode, prot);
+ 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
+ {
+ *filename_opened = concat (current_directory, "/", filename);
+ }
+
+ return fd;
+}
+
+/* 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 = (int *) xmalloc (lines_allocated * sizeof (int));
+ extern int exec_mtime;
+
+ if (fstat (desc, &st) < 0)
+ perror_with_name (s->filename);
+ if (get_exec_file (0) != 0 && exec_mtime < st.st_mtime)
+ printf ("Source file is more recent than executable.\n");
+
+ data = (char *) alloca (st.st_size);
+ if (myread (desc, data, st.st_size) < 0)
+ perror_with_name (s->filename);
+ end = data + st.st_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 *) xrealloc (line_charpos,
+ sizeof (int) * lines_allocated);
+ }
+ line_charpos[nlines++] = p - data;
+ }
+ }
+ s->nlines = nlines;
+ s->line_charpos = (int *) xrealloc (line_charpos, nlines * sizeof (int));
+}
+
+/* Return the character position of a line LINE in symtab S.
+ Return 0 if anything is invalid. */
+
+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;
+}
+
+/* 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. */
+
+int
+get_filename_and_charpos (s, line, fullname)
+ struct symtab *s;
+ int line;
+ char **fullname;
+{
+ register int desc, linenums_changed = 0;
+
+ desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
+ 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)
+ struct symtab *s;
+ int line;
+ int mid_statement;
+{
+ if (s->line_charpos == 0)
+ get_filename_and_charpos (s, line, 0);
+ if (s->fullname == 0)
+ return 0;
+ printf ("\032\032%s:%d:%d:%s:0x%x\n", s->fullname,
+ line, s->line_charpos[line - 1],
+ mid_statement ? "middle" : "beg",
+ get_frame_pc (get_current_frame()));
+ 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;
+
+ desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
+ if (desc < 0)
+ {
+ extern int errno;
+ if (noerror && line + 1 == stopline)
+ {
+ /* can't find the file - tell user where we are anyway */
+ current_source_symtab = s;
+ current_source_line = line;
+ first_line_listed = line;
+ last_line_listed = line;
+ printf_filtered ("%d\t(%s)\n", current_source_line++, s->filename);
+ }
+ else
+ {
+ if (! noerror)
+ perror_with_name (s->filename);
+ print_sys_errmsg (s->filename, 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);
+ }
+
+ current_source_symtab = s;
+ current_source_line = line;
+ first_line_listed = line;
+
+ stream = fdopen (desc, "r");
+ 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')
+ 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("file: \"%s\", line number: %d\n",
+ sals->sals[i].symtab->filename, sals->sals[i].line);
+}
+
+
+static void
+file_command(arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct symbol *sym;
+ char *arg1;
+ int linenum_beg = 0;
+ char *p;
+
+ if (symtab_list == 0 && partial_symtab_list == 0)
+ error ("No symbol table is loaded. Use the \"symbol-file\" command.");
+
+ /* Pull in a current source symtab if necessary */
+ if (arg == 0 || arg[0] == 0) {
+ if (current_source_symtab == 0)
+ select_source_symtab(0);
+ else
+ printf("%s\n", current_source_symtab->filename);
+ return;
+ }
+ arg1 = arg;
+ sals = decode_line_1 (&arg1, 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);
+
+ /* if line was specified by address,
+ 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)
+ error ("No source file for address 0x%x.", sal.pc);
+ sym = find_pc_function (sal.pc);
+ if (sym)
+ printf ("0x%x is in %s (%s, line %d).\n",
+ sal.pc, SYMBOL_NAME (sym), sal.symtab->filename, sal.line);
+ else
+ printf ("0x%x is in %s, line %d.\n",
+ sal.pc, 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 (sal.symtab == 0)
+ {
+ if (! linenum_beg)
+ error ("No line number known for %s.", arg);
+ else
+ error ("No default source file yet. Do \"help list\".");
+ }
+ else
+ {
+ current_source_symtab = sal.symtab;
+ current_source_line = sal.line;
+ first_line_listed = sal.line;
+ }
+}
+
+#define PUSH_STACK_SIZE 32
+static struct {
+ struct symtab *symtab;
+ int line;
+} push_stack[PUSH_STACK_SIZE];
+
+static unsigned int push_stack_ptr;
+
+static void
+push_to_file_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ struct symtab *cursym = current_source_symtab;
+ int curline = current_source_line;
+ register unsigned int i;
+
+ file_command(arg, from_tty);
+
+ /* if we got back, command was successful */
+ i = push_stack_ptr;
+ push_stack[i].symtab = cursym;
+ push_stack[i].line = curline;
+ push_stack_ptr = (i + 1) & (PUSH_STACK_SIZE - 1);
+}
+
+static void
+pop_file_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ register unsigned int i = push_stack_ptr;
+
+ /* if there's something on the stack, pop it & clear the slot. */
+ i = (i + (PUSH_STACK_SIZE - 1)) & (PUSH_STACK_SIZE - 1);
+ if (push_stack[i].symtab) {
+ current_source_symtab = push_stack[i].symtab;
+ first_line_listed = current_source_line = push_stack[i].line;
+ push_stack[i].symtab = NULL;
+ push_stack_ptr = i;
+ }
+}
+
+
+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 (symtab_list == 0 && partial_symtab_list == 0)
+ error ("No symbol table is loaded. Use the \"symbol-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 || !strcmp (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 + 10, 0);
+ return;
+ }
+
+ /* "l -" lists previous ten lines, the ones before the ten just listed. */
+ if (!strcmp (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 - 10, 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);
+
+ 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);
+ else
+ sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line);
+ 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)
+ error ("No source file for address 0x%x.", sal.pc);
+ sym = find_pc_function (sal.pc);
+ if (sym)
+ printf ("0x%x is in %s (%s, line %d).\n",
+ sal.pc, SYMBOL_NAME (sym), sal.symtab->filename, sal.line);
+ else
+ printf ("0x%x is in %s, line %d.\n",
+ sal.pc, 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 - 9, 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 - 5, 1), sal.line + 5, 0);
+ else
+ print_source_lines (sal.symtab, sal.line,
+ dummy_end ? sal.line + 10 : 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;
+ int 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);
+
+ /* If this command is repeated with RET,
+ turn it into the no-arg variant. */
+ if (from_tty)
+ *arg = 0;
+ }
+
+ /* 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)
+ error ("No source file specified.");
+
+ if (sal.line > 0
+ && find_line_pc_range (sal.symtab, sal.line, &start_pc, &end_pc))
+ {
+ if (start_pc == end_pc)
+ printf ("Line %d of \"%s\" is at pc 0x%x but contains no code.\n",
+ sal.line, sal.symtab->filename, start_pc);
+ else
+ printf ("Line %d of \"%s\" starts at pc 0x%x and ends at 0x%x.\n",
+ sal.line, sal.symtab->filename, start_pc, end_pc);
+ /* 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;
+ }
+ else
+ printf ("Line number %d is out of range for \"%s\".\n",
+ sal.line, sal.symtab->filename);
+ }
+}
+
+/* Commands to search the source file for a regexp. */
+
+static void
+forward_search_command (regex, from_tty)
+ char *regex;
+{
+ 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 = openp (source_path, 0, current_source_symtab->filename,
+ O_RDONLY, 0, &current_source_symtab->fullname);
+ 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, "r");
+ clearerr (stream);
+ while (1) {
+ char buf[4096]; /* Should be reasonable??? */
+ register char *p = buf;
+
+ c = fgetc (stream);
+ if (c == EOF)
+ break;
+ do {
+ *p++ = c;
+ } while (c != '\n' && (c = fgetc (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 - 5, 1);
+ return;
+ }
+ line++;
+ }
+
+ printf ("Expression not found\n");
+ fclose (stream);
+}
+
+static void
+reverse_search_command (regex, from_tty)
+ char *regex;
+{
+ 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 = openp (source_path, 0, current_source_symtab->filename,
+ O_RDONLY, 0, &current_source_symtab->fullname);
+ 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, "r");
+ clearerr (stream);
+ while (1)
+ {
+ char buf[4096]; /* Should be reasonable??? */
+ register char *p = buf;
+
+ c = fgetc (stream);
+ if (c == EOF)
+ break;
+ do {
+ *p++ = c;
+ } while (c != '\n' && (c = fgetc (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 - 5, 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 ("Expression not found\n");
+ fclose (stream);
+ return;
+}
+
+void
+_initialize_source ()
+{
+ current_source_symtab = 0;
+ init_source_path ();
+
+ add_com ("directory", class_files, directory_command,
+ "Add directory DIR to end of search path for source files.\n\
+With no argument, reset the search path to just the working directory\n\
+and forget cached info on line positions in source files.");
+
+ add_info ("directories", directories_info,
+ "Current search path for finding source files.");
+
+ 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 ("file", class_files, file_command,
+ "Select current file, function and line for display or list.\n\
+Specification can have the form:\n\
+ LINENUM, to select that line in current file,\n\
+ FILE:LINENUM, to select that line in that file,\n\
+ FUNCTION, to select beginning of that function,\n\
+ FILE:FUNCTION, to distinguish among like-named static functions.\n\
+ *ADDRESS, to select the line containing that address.");
+ add_com ("push-to-file", class_files, push_to_file_command,
+ "Like \"file\" command but remembers current file & line on a stack.\n\
+Can later return to current file with \"pop-file\" command.\n\
+Up to 32 file positions can be pushed on stack.");
+ add_com ("pop-file", class_files, pop_file_command,
+ "Pops back to file position saved by most recent \"push-to-file\".\n\
+If everything has been popped from stack, command does nothing.");
+}
+
diff --git a/gnu/usr.bin/gdb/stab.def b/gnu/usr.bin/gdb/stab.def
new file mode 100644
index 0000000..b81cda4
--- /dev/null
+++ b/gnu/usr.bin/gdb/stab.def
@@ -0,0 +1,115 @@
+/* Table of DBX symbol codes for the GNU system.
+ 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. */
+
+/* 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. */
+__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.
+ This is not used in C. */
+__define_stab (N_MAIN, 0x2a, "MAIN")
+
+/* Register variable. Value is number of register. */
+__define_stab (N_RSYM, 0x40, "RSYM")
+
+/* Structure or union element. Value is offset in the structure. */
+__define_stab (N_SSYM, 0x60, "SSYM")
+
+/* 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")
+
+/* Automatic variable in the stack. Value is offset from frame pointer.
+ Also used for type descriptions. */
+__define_stab (N_LSYM, 0x80, "LSYM")
+
+/* Alternate entry point. Value is its address. */
+__define_stab (N_ENTRY, 0xa4, "ENTRY")
+
+/* Name of main source file.
+ Value is starting text address of the compilation. */
+__define_stab (N_SO, 0x64, "SO")
+
+/* Name of sub-source file.
+ Value is starting text address of the compilation. */
+__define_stab (N_SOL, 0x84, "SOL")
+
+/* Line number in text segment. Desc is the line number;
+ value is corresponding address. */
+__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")
+
+/* 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")
+/* End of an include file. No name.
+ These two 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")
+/* Place holder for deleted include file.
+ This appears only in output from the Sun linker. */
+__define_stab (N_EXCL, 0xc2, "EXCL")
+
+/* 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. */
+__define_stab (N_LBRAC, 0xc0, "LBRAC")
+/* 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. */
+__define_stab (N_RBRAC, 0xe0, "RBRAC")
+
+/* Begin named common block. Only the name is significant. */
+__define_stab (N_BCOMM, 0xe2, "BCOMM")
+/* Begin named common block. Only the name is significant
+ (and it should match the N_BCOMM). */
+__define_stab (N_ECOMM, 0xe4, "ECOMM")
+/* End common (local name): value is address.
+ I'm not sure how this is used. */
+__define_stab (N_ECOML, 0xe8, "ECOML")
+/* Second symbol entry containing a length-value for the preceding entry.
+ The value is the length. */
+__define_stab (N_LENG, 0xfe, "LENG")
+
+/* Global symbol in Pascal.
+ Supposedly the value is its line number; I'm skeptical. */
+__define_stab (N_PC, 0x30, "PC")
+
+/* Modula-2 compilation unit. Can someone say what info it contains? */
+__define_stab (N_M2C, 0x42, "M2C")
+/* Modula-2 scope information. Can someone say what info it contains? */
+__define_stab (N_SCOPE, 0xc4, "SCOPE")
diff --git a/gnu/usr.bin/gdb/stack.c b/gnu/usr.bin/gdb/stack.c
new file mode 100644
index 0000000..91218aa
--- /dev/null
+++ b/gnu/usr.bin/gdb/stack.c
@@ -0,0 +1,960 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)stack.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Print and select stack frames 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. */
+
+/* modified by rjc Thu Nov 1 16:46:57 1990, fixed return_command so that
+ it can return values, it still has problems when running on pmax,
+ cannot write register 65 */
+
+#include <stdio.h>
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "value.h"
+
+
+/* Thie "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;
+
+/* Nonzero means print the full filename and linenumber
+ when a frame is printed, and do so in a format programs can parse. */
+
+int frame_file_full_name = 0;
+
+static void select_calling_frame ();
+
+void print_frame_info ();
+
+/* 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. */
+
+static void
+print_stack_frame (frame, level, source)
+ FRAME frame;
+ int level;
+ int source;
+{
+ struct frame_info *fi;
+
+ fi = get_frame_info (frame);
+
+ print_frame_info (fi, level, source, 1);
+}
+
+/* Flag which will indicate when the frame has been changed
+ by and "up" or "down" command. */
+static int frame_changed;
+
+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;
+ int numargs;
+ struct partial_symtab *pst;
+
+ /* Don't give very much information if we haven't readin the
+ symbol table yet. */
+ pst = find_pc_psymtab (fi->pc);
+ if (pst && !pst->readin)
+ {
+ /* Abbreviated information. */
+ char *fname;
+
+ if (!find_pc_partial_function (fi->pc, &fname, 0))
+ fname = "??";
+
+ printf_filtered ("#%-2d ", level);
+ printf_filtered ("0x%x in ", fi->pc);
+
+ fputs_demangled(fname, stdout, -1);
+ fputs_filtered(" (...)\n", stdout);
+
+ return;
+ }
+
+ sal = find_pc_line (fi->pc, fi->next_frame);
+ 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).
+
+ So look in the misc_function_vector 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
+ misc_function_vector symbols in the middle of a function. */
+ int misc_index = find_pc_misc_function (fi->pc);
+ if (misc_index >= 0
+ && (misc_function_vector[misc_index].address
+ > BLOCK_START (SYMBOL_BLOCK_VALUE (func))))
+ {
+ /* In this case we have no way of knowing the source file
+ and line number, so don't print them. */
+ sal.symtab = 0;
+ /* We also don't know anything about the function besides
+ its address and name. */
+ func = 0;
+ funname = misc_function_vector[misc_index].name;
+ }
+ else
+ funname = SYMBOL_NAME (func);
+ }
+ else
+ {
+ register int misc_index = find_pc_misc_function (fi->pc);
+ if (misc_index >= 0)
+ funname = misc_function_vector[misc_index].name;
+ }
+
+ if (frame_changed || source >= 0 || !sal.symtab)
+ {
+ if (level >= 0)
+ printf_filtered ("#%-2d ", level);
+ else if (frame_changed)
+ printf ("#%-2d ", 0);
+ if (fi->pc != sal.pc || !sal.symtab)
+ printf_filtered ("0x%x in ", fi->pc);
+ fputs_demangled(funname ? funname : "??", stdout, -1);
+ printf_filtered(" (");
+ if (args)
+ {
+ if (func)
+ numargs = -1;
+ else
+ FRAME_NUM_ARGS (numargs, fi);
+
+ print_frame_args (func, fi, numargs, stdout);
+ }
+ printf_filtered (")");
+ if (sal.symtab)
+ printf_filtered (" (%s line %d)", sal.symtab->filename, sal.line);
+ printf_filtered ("\n");
+ }
+
+ if ((frame_changed || source != 0) && sal.symtab)
+ {
+ int done = 0;
+ int mid_statement = source < 0 && fi->pc != sal.pc;
+ if (frame_file_full_name)
+ done = identify_source_line (sal.symtab, sal.line, mid_statement);
+ if (!done)
+ {
+ if (mid_statement)
+ printf_filtered ("0x%x\t", fi->pc);
+ print_source_lines (sal.symtab, sal.line, sal.line + 1, 1);
+ }
+ current_source_line = max (sal.line - 5, 1);
+ }
+ frame_changed = 0;
+ if (source != 0)
+ set_default_breakpoint (1, fi->pc, sal.symtab, sal.line);
+
+ fflush (stdout);
+}
+
+/* Call here to print info on selected frame, after a trap. */
+
+void
+print_sel_frame (just_source)
+ int just_source;
+{
+ print_stack_frame (selected_frame, -1, just_source ? -1 : 1);
+}
+
+/* Print info on the selected frame, including level number
+ but not source. */
+
+void
+print_selected_frame ()
+{
+ print_stack_frame (selected_frame, selected_frame_level, 0);
+}
+
+void flush_cached_frames ();
+
+#ifdef FRAME_SPECIFICATION_DYADIC
+extern FRAME setup_arbitrary_frame ();
+#endif
+
+/*
+ * Read a frame specification in whatever the appropriate format is.
+ */
+static FRAME
+parse_frame_specification (frame_exp)
+ char *frame_exp;
+{
+ int numargs = 0;
+ int arg1, arg2;
+
+ if (frame_exp)
+ {
+ char *addr_string, *p;
+ struct cleanup *tmp_cleanup;
+ struct frame_info *fci;
+
+ while (*frame_exp == ' ') frame_exp++;
+ for (p = frame_exp; *p && *p != ' '; p++)
+ ;
+
+ if (*frame_exp)
+ {
+ numargs = 1;
+ addr_string = savestring(frame_exp, p - frame_exp);
+
+ {
+ tmp_cleanup = make_cleanup (free, addr_string);
+ arg1 = parse_and_eval_address (addr_string);
+ do_cleanups (tmp_cleanup);
+ }
+
+ while (*p == ' ') p++;
+
+ if (*p)
+ {
+ numargs = 2;
+ arg2 = parse_and_eval_address (p);
+ }
+ }
+ }
+
+ switch (numargs)
+ {
+ case 0:
+ return selected_frame;
+ /* NOTREACHED */
+ case 1:
+ {
+ int level = arg1;
+ FRAME fid = find_relative_frame (get_current_frame (), &level);
+ FRAME tfid;
+
+ if (level == 0)
+ /* find_relative_frame was successful */
+ return fid;
+
+ /* 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) != arg1;
+ fid = get_prev_frame (fid))
+ ;
+
+ if (fid)
+ while ((tfid = get_prev_frame (fid)) &&
+ (FRAME_FP (tfid) == arg1))
+ fid = tfid;
+
+#ifdef FRAME_SPECIFICATION_DYADIC
+ if (!fid)
+ error ("Incorrect number of args in frame specification");
+
+ return fid;
+#else
+ return create_new_frame (arg1, 0);
+#endif
+ }
+ /* NOTREACHED */
+ case 2:
+ /* Must be addresses */
+#ifndef FRAME_SPECIFICATION_DYADIC
+ error ("Incorrect number of args in frame specification");
+#else
+ return setup_arbitrary_frame (arg1, arg2);
+#endif
+ /* NOTREACHED */
+ }
+ fatal ("Internal: Error in parsing in parse_frame_specification");
+ /* NOTREACHED */
+}
+
+/* FRAME_ARGS_ADDRESS_CORRECT is just like FRAME_ARGS_ADDRESS except
+ that if it is unsure about the answer, it returns Frame_unknown
+ instead of guessing (this happens on the VAX, 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)
+ char *addr_exp;
+{
+ FRAME frame;
+ struct frame_info *fi;
+ struct frame_saved_regs fsr;
+ struct symtab_and_line sal;
+ struct symbol *func;
+ FRAME calling_frame;
+ int i, count;
+ char *funname = 0;
+
+ if (!(have_inferior_p () || have_core_file_p ()))
+ error ("No inferior or core file.");
+
+ frame = parse_frame_specification (addr_exp);
+ if (!frame)
+ error ("Invalid frame specified.");
+
+ fi = get_frame_info (frame);
+ get_frame_saved_regs (fi, &fsr);
+ sal = find_pc_line (fi->pc, fi->next_frame);
+ func = get_frame_function (frame);
+ if (func)
+ funname = SYMBOL_NAME (func);
+ else
+ {
+ register int misc_index = find_pc_misc_function (fi->pc);
+ if (misc_index >= 0)
+ funname = misc_function_vector[misc_index].name;
+ }
+ calling_frame = get_prev_frame (frame);
+
+ if (!addr_exp && selected_frame_level >= 0)
+ printf ("Stack level %d, frame at 0x%x:\n pc = 0x%x",
+ selected_frame_level, FRAME_FP(frame), fi->pc);
+ else
+ printf ("Stack frame at 0x%x:\n pc = 0x%x",
+ FRAME_FP(frame), fi->pc);
+
+ if (funname)
+ printf (" in %s", funname);
+ if (sal.symtab)
+ printf (" (%s line %d)", sal.symtab->filename, sal.line);
+ printf ("; saved pc 0x%x\n", FRAME_SAVED_PC (frame));
+ if (calling_frame)
+ printf (" called by frame at 0x%x", FRAME_FP (calling_frame));
+ if (fi->next_frame && calling_frame)
+ printf (",");
+ if (fi->next_frame)
+ printf (" caller of frame at 0x%x", fi->next_frame);
+ if (fi->next_frame || calling_frame)
+ printf ("\n");
+
+ {
+ /* Address of the argument list for this frame, or Frame_unknown. */
+ CORE_ADDR arg_list = FRAME_ARGS_ADDRESS_CORRECT (fi);
+ /* Number of args for this frame, or -1 if unknown. */
+ int numargs;
+
+ if (arg_list != Frame_unknown)
+ {
+ printf (" Arglist at 0x%x,", arg_list);
+
+ FRAME_NUM_ARGS (numargs, fi);
+ if (numargs < 0)
+ printf (" args: ");
+ else if (numargs == 0)
+ printf (" no args.");
+ else if (numargs == 1)
+ printf (" 1 arg: ");
+ else
+ printf (" %d args: ", numargs);
+ print_frame_args (func, fi, numargs, stdout);
+ printf ("\n");
+ }
+ }
+
+ /* The sp is special; what's returned isn't the save address, but
+ actually the value of the previous frame's sp. */
+ printf (" Previous frame's sp is 0x%x\n", fsr.regs[SP_REGNUM]);
+ count = 0;
+ for (i = 0; i < NUM_REGS; i++)
+ if (fsr.regs[i] && i != SP_REGNUM)
+ {
+ if (count % 4 != 0)
+ printf (", ");
+ else
+ {
+ if (count == 0)
+ printf (" Saved registers:");
+ printf ("\n ");
+ }
+ printf ("%s at 0x%x", reg_names[i], fsr.regs[i]);
+ count++;
+ }
+ if (count)
+ printf ("\n");
+}
+
+#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 ("Backtrace limit: %d.\n", backtrace_limit);
+}
+#endif
+
+/* Print briefly all stack frames or just the innermost COUNT frames. */
+
+static void
+backtrace_command (count_exp)
+ char *count_exp;
+{
+ struct frame_info *fi;
+ register int count;
+ register FRAME frame;
+ register int i;
+ register FRAME trailing;
+ register int trailing_level;
+
+ /* 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--)
+ current = get_prev_frame (current);
+
+ /* Will stop when CURRENT reaches the top of the stack. TRAILING
+ will be COUNT below it. */
+ while (current)
+ {
+ trailing = get_prev_frame (trailing);
+ current = get_prev_frame (current);
+ trailing_level++;
+ }
+
+ count = -1;
+ }
+ }
+ else
+ count = -1;
+
+ for (i = 0, frame = trailing;
+ frame && count--;
+ i++, frame = get_prev_frame (frame))
+ {
+ QUIT;
+ fi = get_frame_info (frame);
+ print_frame_info (fi, trailing_level + i, 0, 1);
+ }
+
+ /* If we've stopped before the end, mention that. */
+ if (frame)
+ 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 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 (SYMBOL_CLASS (sym) == LOC_LOCAL
+ || SYMBOL_CLASS (sym) == LOC_REGISTER
+ || SYMBOL_CLASS (sym) == LOC_STATIC)
+ {
+ values_printed = 1;
+ fputs_filtered (SYMBOL_NAME (sym), stream);
+ fputs_filtered (" = ", stream);
+ print_variable_value (sym, frame, stream);
+ fprintf_filtered (stream, "\n");
+ fflush (stream);
+ }
+ }
+ 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 int
+print_frame_local_vars (frame, stream)
+ register FRAME frame;
+ register 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");
+ fflush (stream);
+ return 0;
+ }
+
+ 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");
+ fflush (stream);
+ }
+
+ return 1;
+}
+
+static void
+locals_info ()
+{
+ if (!have_inferior_p () && !have_core_file_p ())
+ error ("No inferior or core file.");
+
+ print_frame_local_vars (selected_frame, stdout);
+}
+
+static int
+print_frame_arg_vars (frame, stream)
+ register FRAME frame;
+ register FILE *stream;
+{
+ struct symbol *func = get_frame_function (frame);
+ register struct block *b;
+ int nsyms;
+ register int i;
+ register struct symbol *sym;
+ register int values_printed = 0;
+
+ if (func == 0)
+ {
+ fprintf_filtered (stream, "No symbol table info available.\n");
+ fflush (stream);
+ return 0;
+ }
+
+ b = SYMBOL_BLOCK_VALUE (func);
+ nsyms = BLOCK_NSYMS (b);
+
+ for (i = 0; i < nsyms; i++)
+ {
+ sym = BLOCK_SYM (b, i);
+ if (SYMBOL_CLASS (sym) == LOC_ARG
+ || SYMBOL_CLASS (sym) == LOC_REF_ARG
+ || SYMBOL_CLASS (sym) == LOC_REGPARM)
+ {
+ values_printed = 1;
+ fputs_filtered (SYMBOL_NAME (sym), stream);
+ fputs_filtered (" = ", stream);
+ print_variable_value (sym, frame, stream);
+ fprintf_filtered (stream, "\n");
+ fflush (stream);
+ }
+ }
+
+ if (!values_printed)
+ {
+ fprintf_filtered (stream, "No arguments.\n");
+ fflush (stream);
+ }
+
+ return 1;
+}
+
+static void
+args_info ()
+{
+ if (!have_inferior_p () && !have_core_file_p ())
+ error ("No inferior or core file.");
+ print_frame_arg_vars (selected_frame, 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;
+{
+ selected_frame = frame;
+ selected_frame_level = level;
+ /* Ensure that symbols for this frame are readin. */
+ if (frame)
+ find_pc_symtab (get_frame_info (frame)->pc);
+}
+
+/* Store the selected frame and its level into *FRAMEP and *LEVELP. */
+
+void
+record_selected_frame (frameaddrp, levelp)
+ FRAME_ADDR *frameaddrp;
+ int *levelp;
+{
+ *frameaddrp = FRAME_FP (selected_frame);
+ *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 (!have_inferior_p () && !have_core_file_p ())
+ 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, frame2;
+
+ /* 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 could be done by iterating get_frame_info to
+ find the next frame, but that would be quadratic
+ since get_frame_info must scan all the way from the current frame.
+ The following algorithm is linear. */
+ if (*level_offset_ptr < 0)
+ {
+ /* First put frame1 at innermost frame
+ and frame2 N levels up from there. */
+ frame1 = get_current_frame ();
+ frame2 = frame1;
+ while (*level_offset_ptr < 0 && frame2 != frame)
+ {
+ frame2 = get_prev_frame (frame2);
+ (*level_offset_ptr) ++;
+ }
+ /* Then slide frame1 and frame2 up in synchrony
+ and when frame2 reaches our starting point
+ frame1 must be N levels down from there. */
+ while (frame2 != frame)
+ {
+ frame1 = get_prev_frame (frame1);
+ frame2 = get_prev_frame (frame2);
+ }
+ return frame1;
+ }
+ return frame;
+}
+
+/* The "frame" command. With no arg, print selected frame briefly.
+ 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 print it. See parse_frame_specification for more info on proper
+ frame expressions. */
+
+static void
+frame_command (level_exp, from_tty)
+ char *level_exp;
+ int from_tty;
+{
+ register FRAME frame, frame1;
+ unsigned int level = 0;
+
+ if (!have_inferior_p () && ! have_core_file_p ())
+ error ("No inferior or core file.");
+
+ frame = parse_frame_specification (level_exp);
+
+ for (frame1 = get_prev_frame (0);
+ frame1 && frame1 != frame;
+ frame1 = get_prev_frame (frame1))
+ level++;
+
+ if (!frame1)
+ level = 0;
+
+ frame_changed = level;
+ select_frame (frame, level);
+
+ if (!from_tty)
+ return;
+
+ 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. */
+
+static void
+up_command (count_exp)
+ char *count_exp;
+{
+ register FRAME frame;
+ int count = 1, count1;
+ if (count_exp)
+ count = parse_and_eval_address (count_exp);
+ count1 = count;
+
+ if (!have_inferior_p () && !have_core_file_p ())
+ error ("No inferior or core file.");
+
+ 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);
+
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+ frame_changed++;
+}
+
+/* Select the frame down one or COUNT stack levels
+ from the previously selected frame, and print it briefly. */
+
+static void
+down_command (count_exp)
+ char *count_exp;
+{
+ register FRAME frame;
+ int count = -1, count1;
+ if (count_exp)
+ count = - parse_and_eval_address (count_exp);
+ count1 = count;
+
+ frame = find_relative_frame (selected_frame, &count1);
+ if (count1 != 0 && count_exp == 0)
+ error ("Bottom (i.e., innermost) frame selected; you cannot go down.");
+ select_frame (frame, selected_frame_level + count - count1);
+
+ print_stack_frame (selected_frame, selected_frame_level, 1);
+ frame_changed--;
+}
+
+static void
+return_command (retval_exp, from_tty)
+ char *retval_exp;
+ int from_tty;
+{
+ value return_value;
+ struct symbol *thisfun = get_frame_function (selected_frame);
+ FRAME_ADDR selected_frame_addr = FRAME_FP (selected_frame);
+
+ /* If interactive, require confirmation. */
+
+ if (from_tty)
+ {
+ if (thisfun != 0)
+ {
+ if (!query ("Make %s return now? ", SYMBOL_NAME (thisfun)))
+ error ("Not confirmed.");
+ }
+ 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. Note that this will not work if the selected frame
+ shares it's fp with another frame. */
+
+ while (selected_frame_addr != FRAME_FP (get_current_frame()))
+ POP_FRAME;
+
+ /* get the return value while still in this frame */
+ if (retval_exp)
+ return_value = parse_and_eval (retval_exp);
+
+ /* Then pop that frame. */
+ POP_FRAME;
+
+ /* Store the return value if there was one */
+
+ if (retval_exp)
+ set_return_value (return_value);
+
+ /* If interactive, print the frame that is now current. */
+
+ if (from_tty)
+ frame_command ("0", 1);
+}
+
+extern struct cmd_list_element *setlist;
+
+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 ("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 ("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 ("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.");
+
+#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/symmisc.c b/gnu/usr.bin/gdb/symmisc.c
new file mode 100644
index 0000000..bb4eb50
--- /dev/null
+++ b/gnu/usr.bin/gdb/symmisc.c
@@ -0,0 +1,584 @@
+/* Do various things to symbol tables (other than lookup)), for GDB.
+ 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. */
+
+
+#include "defs.h"
+#include "symtab.h"
+
+#include <stdio.h>
+#include <obstack.h>
+
+static void free_symtab ();
+
+
+/* Free all the symtabs that are currently installed,
+ and all storage associated with them.
+ Leaves us in a consistent state with no symtabs installed. */
+
+void
+free_all_symtabs ()
+{
+ register struct symtab *s, *snext;
+
+ /* All values will be invalid because their types will be! */
+
+ clear_value_history ();
+ clear_displays ();
+ clear_internalvars ();
+ clear_breakpoints ();
+ set_default_breakpoint (0, 0, 0, 0);
+
+ current_source_symtab = 0;
+
+ for (s = symtab_list; s; s = snext)
+ {
+ snext = s->next;
+ free_symtab (s);
+ }
+ symtab_list = 0;
+ obstack_free (symbol_obstack, 0);
+ obstack_init (symbol_obstack);
+
+ if (misc_function_vector)
+ free (misc_function_vector);
+ misc_function_count = 0;
+ misc_function_vector = 0;
+}
+
+/* Free a struct block <- B and all the symbols defined in that block. */
+
+static void
+free_symtab_block (b)
+ struct block *b;
+{
+ register int i, n;
+ n = BLOCK_NSYMS (b);
+ for (i = 0; i < n; i++)
+ {
+ free (SYMBOL_NAME (BLOCK_SYM (b, i)));
+ free (BLOCK_SYM (b, i));
+ }
+ free (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. */
+
+static void
+free_symtab (s)
+ register struct symtab *s;
+{
+ register int i, n;
+ register struct blockvector *bv;
+ register struct type *type;
+ register struct typevector *tv;
+
+ switch (s->free_code)
+ {
+ case free_nothing:
+ /* All the contents are part of a big block of memory
+ 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 (BLOCKVECTOR_BLOCK (bv, i));
+ /* Free the blockvector itself. */
+ free (bv);
+ /* Free the type vector. */
+ tv = TYPEVECTOR (s);
+ free (tv);
+ /* Also free the linetable. */
+
+ case free_linetable:
+ /* Everything will be freed either by our `free_ptr'
+ or by some other symbatb, except for our linetable.
+ Free that now. */
+ free (LINETABLE (s));
+ break;
+ }
+
+ /* If there is a single block of memory to free, free it. */
+ if (s->free_ptr)
+ free (s->free_ptr);
+
+ if (s->line_charpos)
+ free (s->line_charpos);
+ free (s->filename);
+ free (s);
+}
+
+/* Convert a raw symbol-segment to a struct symtab,
+ and relocate its internal pointers so that it is valid. */
+
+/* This is how to relocate one pointer, given a name for it.
+ Works independent of the type of object pointed to. */
+#define RELOCATE(slot) (slot ? (* (char **) &slot += relocation) : 0)
+
+/* This is the inverse of RELOCATE. We use it when storing
+ a core address into a slot that has yet to be relocated. */
+#define UNRELOCATE(slot) (slot ? (* (char **) &slot -= relocation) : 0)
+
+/* During the process of relocation, this holds the amount to relocate by
+ (the address of the file's symtab data, in core in the debugger). */
+static int relocation;
+
+#define CORE_RELOCATE(slot) \
+ ((slot) += (((slot) < data_start) ? text_relocation \
+ : ((slot) < bss_start) ? data_relocation : bss_relocation))
+
+#define TEXT_RELOCATE(slot) ((slot) += text_relocation)
+
+/* Relocation amounts for addresses in the program's core image. */
+static int text_relocation, data_relocation, bss_relocation;
+
+/* Boundaries that divide program core addresses into text, data and bss;
+ used to determine which relocation amount to use. */
+static int data_start, bss_start;
+
+static void relocate_typevector ();
+static void relocate_blockvector ();
+static void relocate_type ();
+static void relocate_block ();
+static void relocate_symbol ();
+static void relocate_source ();
+
+/* Relocate a file's symseg so that all the pointers are valid C pointers.
+ Value is a `struct symtab'; but it is not suitable for direct
+ insertion into the `symtab_list' because it describes several files. */
+
+static struct symtab *
+relocate_symtab (root)
+ struct symbol_root *root;
+{
+ struct symtab *sp = (struct symtab *) xmalloc (sizeof (struct symtab));
+ bzero (sp, sizeof (struct symtab));
+
+ relocation = (int) root;
+ text_relocation = root->textrel;
+ data_relocation = root->datarel;
+ bss_relocation = root->bssrel;
+ data_start = root->databeg;
+ bss_start = root->bssbeg;
+
+ sp->filename = root->filename;
+ sp->ldsymoff = root->ldsymoff;
+ sp->language = root->language;
+ sp->compilation = root->compilation;
+ sp->version = root->version;
+ sp->blockvector = root->blockvector;
+ sp->typevector = root->typevector;
+
+ RELOCATE (TYPEVECTOR (sp));
+ RELOCATE (BLOCKVECTOR (sp));
+ RELOCATE (sp->version);
+ RELOCATE (sp->compilation);
+ RELOCATE (sp->filename);
+
+ relocate_typevector (TYPEVECTOR (sp));
+ relocate_blockvector (BLOCKVECTOR (sp));
+
+ return sp;
+}
+
+static void
+relocate_blockvector (blp)
+ register struct blockvector *blp;
+{
+ register int nblocks = BLOCKVECTOR_NBLOCKS (blp);
+ register int i;
+ for (i = 0; i < nblocks; i++)
+ RELOCATE (BLOCKVECTOR_BLOCK (blp, i));
+ for (i = 0; i < nblocks; i++)
+ relocate_block (BLOCKVECTOR_BLOCK (blp, i));
+}
+
+static void
+relocate_block (bp)
+ register struct block *bp;
+{
+ register int nsyms = BLOCK_NSYMS (bp);
+ register int i;
+
+ TEXT_RELOCATE (BLOCK_START (bp));
+ TEXT_RELOCATE (BLOCK_END (bp));
+
+ /* These two should not be recursively processed.
+ The superblock need not be because all blocks are
+ processed from relocate_blockvector.
+ The function need not be because it will be processed
+ under the block which is its scope. */
+ RELOCATE (BLOCK_SUPERBLOCK (bp));
+ RELOCATE (BLOCK_FUNCTION (bp));
+
+ for (i = 0; i < nsyms; i++)
+ RELOCATE (BLOCK_SYM (bp, i));
+
+ for (i = 0; i < nsyms; i++)
+ relocate_symbol (BLOCK_SYM (bp, i));
+}
+
+static void
+relocate_symbol (sp)
+ register struct symbol *sp;
+{
+ RELOCATE (SYMBOL_NAME (sp));
+ if (SYMBOL_CLASS (sp) == LOC_BLOCK)
+ {
+ RELOCATE (SYMBOL_BLOCK_VALUE (sp));
+ /* We can assume the block that belongs to this symbol
+ is not relocated yet, since it comes after
+ the block that contains this symbol. */
+ BLOCK_FUNCTION (SYMBOL_BLOCK_VALUE (sp)) = sp;
+ UNRELOCATE (BLOCK_FUNCTION (SYMBOL_BLOCK_VALUE (sp)));
+ }
+ else if (SYMBOL_CLASS (sp) == LOC_STATIC)
+ CORE_RELOCATE (SYMBOL_VALUE (sp));
+ else if (SYMBOL_CLASS (sp) == LOC_LABEL)
+ TEXT_RELOCATE (SYMBOL_VALUE (sp));
+ RELOCATE (SYMBOL_TYPE (sp));
+}
+
+static void
+relocate_typevector (tv)
+ struct typevector *tv;
+{
+ register int ntypes = TYPEVECTOR_NTYPES (tv);
+ register int i;
+
+ for (i = 0; i < ntypes; i++)
+ RELOCATE (TYPEVECTOR_TYPE (tv, i));
+ for (i = 0; i < ntypes; i++)
+ relocate_type (TYPEVECTOR_TYPE (tv, i));
+}
+
+/* We cannot come up with an a priori spanning tree
+ for the network of types, since types can be used
+ for many symbols and also as components of other types.
+ Therefore, we need to be able to mark types that we
+ already have relocated (or are already in the middle of relocating)
+ as in a garbage collector. */
+
+static void
+relocate_type (tp)
+ register struct type *tp;
+{
+ register int nfields = TYPE_NFIELDS (tp);
+ register int i;
+
+ RELOCATE (TYPE_NAME (tp));
+ RELOCATE (TYPE_TARGET_TYPE (tp));
+ RELOCATE (TYPE_FIELDS (tp));
+ RELOCATE (TYPE_POINTER_TYPE (tp));
+
+ for (i = 0; i < nfields; i++)
+ {
+ RELOCATE (TYPE_FIELD_TYPE (tp, i));
+ RELOCATE (TYPE_FIELD_NAME (tp, i));
+ }
+}
+
+static void
+relocate_sourcevector (svp)
+ register struct sourcevector *svp;
+{
+ register int nfiles = svp->length;
+ register int i;
+ for (i = 0; i < nfiles; i++)
+ RELOCATE (svp->source[i]);
+ for (i = 0; i < nfiles; i++)
+ relocate_source (svp->source[i]);
+}
+
+static void
+relocate_source (sp)
+ register struct source *sp;
+{
+ register int nitems = sp->contents.nitems;
+ register int i;
+
+ RELOCATE (sp->name);
+ for (i = 0; i < nitems; i++)
+ TEXT_RELOCATE (sp->contents.item[i].pc);
+}
+
+/* Read symsegs from file named NAME open on DESC,
+ make symtabs from them, and return a chain of them.
+ These symtabs are not suitable for direct use in `symtab_list'
+ because each one describes a single object file, perhaps many source files.
+ `symbol_file_command' takes each of these, makes many real symtabs
+ from it, and then frees it.
+
+ We assume DESC is prepositioned at the end of the string table,
+ just before the symsegs if there are any. */
+
+struct symtab *
+read_symsegs (desc, name)
+ int desc;
+ char *name;
+{
+ struct symbol_root root;
+ register char *data;
+ register struct symtab *sp, *sp1, *chain = 0;
+ register int len;
+
+ while (1)
+ {
+ len = myread (desc, &root, sizeof root);
+ if (len == 0 || root.format == 0)
+ break;
+ /* format 1 was ok for the original gdb, but since the size of the
+ type structure changed when C++ support was added, it can no
+ longer be used. Accept only format 2. */
+ if (root.format != 2 ||
+ root.length < sizeof root)
+ error ("\nInvalid symbol segment format code");
+ data = (char *) xmalloc (root.length);
+ bcopy (&root, data, sizeof root);
+ len = myread (desc, data + sizeof root,
+ root.length - sizeof root);
+ sp = relocate_symtab (data);
+ RELOCATE (((struct symbol_root *)data)->sourcevector);
+ relocate_sourcevector (((struct symbol_root *)data)->sourcevector);
+ sp->next = chain;
+ chain = sp;
+ sp->linetable = (struct linetable *) ((struct symbol_root *)data)->sourcevector;
+ }
+
+ return chain;
+}
+
+static int block_depth ();
+void print_spaces ();
+static void print_symbol ();
+
+void
+print_symtabs (filename)
+ char *filename;
+{
+ FILE *outfile;
+ register struct symtab *s;
+ register int i, j;
+ int len, line, blen;
+ register struct linetable *l;
+ struct blockvector *bv;
+ register struct block *b;
+ int depth;
+ struct cleanup *cleanups;
+ extern int fclose();
+
+ if (filename == 0)
+ error_no_arg ("file to write symbol data in");
+
+ filename = tilde_expand (filename);
+ make_cleanup (free, filename);
+
+ outfile = fopen (filename, "w");
+ if (outfile == 0)
+ perror_with_name (filename);
+
+ cleanups = make_cleanup (fclose, outfile);
+ immediate_quit++;
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ /* First print the line table. */
+ fprintf (outfile, "Symtab for file %s\n\n", s->filename);
+ fprintf (outfile, "Line table:\n\n");
+ l = LINETABLE (s);
+ len = l->nitems;
+ for (i = 0; i < len; i++)
+ fprintf (outfile, " line %d at %x\n", l->item[i].line,
+ l->item[i].pc);
+ /* Now print the block info. */
+ fprintf (outfile, "\nBlockvector:\n\n");
+ bv = BLOCKVECTOR (s);
+ 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 (outfile, "block #%03d (object 0x%x) ", i, b);
+ fprintf (outfile, "[0x%x..0x%x]", BLOCK_START (b), BLOCK_END (b));
+ if (BLOCK_SUPERBLOCK (b))
+ fprintf (outfile, " (under 0x%x)", BLOCK_SUPERBLOCK (b));
+ if (BLOCK_FUNCTION (b))
+ fprintf (outfile, " %s", SYMBOL_NAME (BLOCK_FUNCTION (b)));
+ fputc ('\n', outfile);
+ blen = BLOCK_NSYMS (b);
+ for (j = 0; j < blen; j++)
+ {
+ print_symbol (BLOCK_SYM (b, j), depth + 1, outfile);
+ }
+ }
+
+ fprintf (outfile, "\n\n");
+ }
+
+ immediate_quit--;
+ do_cleanups (cleanups);
+}
+
+static void
+print_symbol (symbol, depth, outfile)
+ struct symbol *symbol;
+ int depth;
+ FILE *outfile;
+{
+ print_spaces (depth, outfile);
+ if (SYMBOL_NAMESPACE (symbol) == LABEL_NAMESPACE)
+ {
+ fprintf (outfile, "label %s at 0x%x\n", SYMBOL_NAME (symbol),
+ SYMBOL_VALUE (symbol));
+ return;
+ }
+ if (SYMBOL_NAMESPACE (symbol) == STRUCT_NAMESPACE)
+ {
+ if (TYPE_NAME (SYMBOL_TYPE (symbol)))
+ {
+ type_print_1 (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
+ }
+ else
+ {
+ fprintf (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));
+ type_print_1 (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
+ }
+ fprintf (outfile, ";\n");
+ }
+ else
+ {
+ if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF)
+ fprintf (outfile, "typedef ");
+ if (SYMBOL_TYPE (symbol))
+ {
+ type_print_1 (SYMBOL_TYPE (symbol), SYMBOL_NAME (symbol),
+ outfile, 1, depth);
+ fprintf (outfile, "; ");
+ }
+ else
+ fprintf (outfile, "%s ", SYMBOL_NAME (symbol));
+
+ switch (SYMBOL_CLASS (symbol))
+ {
+ case LOC_CONST:
+ fprintf (outfile, "const %d (0x%x),",
+ SYMBOL_VALUE (symbol), SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_CONST_BYTES:
+ fprintf (outfile, "const %d hex bytes:",
+ TYPE_LENGTH (SYMBOL_TYPE (symbol)));
+ {
+ int i;
+ for (i = 0; i < TYPE_LENGTH (SYMBOL_TYPE (symbol)); i++)
+ fprintf (outfile, " %2x", SYMBOL_VALUE_BYTES (symbol) [i]);
+ fprintf (outfile, ",");
+ }
+ break;
+
+ case LOC_STATIC:
+ fprintf (outfile, "static at 0x%x,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_REGISTER:
+ fprintf (outfile, "register %d,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_ARG:
+ fprintf (outfile, "arg at 0x%x,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_REF_ARG:
+ fprintf (outfile, "reference arg at 0x%x,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_REGPARM:
+ fprintf (outfile, "parameter register %d,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_LOCAL:
+ fprintf (outfile, "local at 0x%x,", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_TYPEDEF:
+ break;
+
+ case LOC_LABEL:
+ fprintf (outfile, "label at 0x%x", SYMBOL_VALUE (symbol));
+ break;
+
+ case LOC_BLOCK:
+ fprintf (outfile, "block (object 0x%x) starting at 0x%x,",
+ SYMBOL_VALUE (symbol),
+ BLOCK_START (SYMBOL_BLOCK_VALUE (symbol)));
+ break;
+ }
+ }
+ fprintf (outfile, "\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)) i++;
+ return i;
+}
+
+/*
+ * Free all partial_symtab storage.
+ */
+void
+free_all_psymtabs()
+{
+ obstack_free (psymbol_obstack, 0);
+ obstack_init (psymbol_obstack);
+ partial_symtab_list = (struct partial_symtab *) 0;
+}
+
+void
+_initialize_symmisc ()
+{
+ symtab_list = (struct symtab *) 0;
+ partial_symtab_list = (struct partial_symtab *) 0;
+
+ add_com ("printsyms", class_obscure, print_symtabs,
+ "Print dump of current symbol definitions to file OUTFILE.");
+}
+
diff --git a/gnu/usr.bin/gdb/symseg.h b/gnu/usr.bin/gdb/symseg.h
new file mode 100644
index 0000000..6a61a17
--- /dev/null
+++ b/gnu/usr.bin/gdb/symseg.h
@@ -0,0 +1,523 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ *
+ * @(#)symseg.h 6.3 (Berkeley) 5/8/91
+ */
+
+/* GDB symbol table format definitions.
+ Copyright (C) 1986, 1989 Free Software Foundation, Inc.
+ Hacked by Michael Tiemann (tiemann@mcc.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. */
+
+/* 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 */
+
+ /* C++ */
+ TYPE_CODE_MEMBER, /* Member type */
+ TYPE_CODE_METHOD, /* Method type */
+ TYPE_CODE_REF, /* C++ Reference types */
+};
+
+/* This appears in a type's flags word for an unsigned integer type. */
+#define TYPE_FLAG_UNSIGNED 1
+/* This appears in a type's flags word
+ if it is a (pointer to a|function returning a)* built in scalar type.
+ These types are never freed. */
+#define TYPE_FLAG_PERM 4
+/* This appears in a type's flags word if it is a stub type (eg. if
+ someone referenced a type that wasn't definined in a source file
+ via (struct sir_not_appearing_in_this_film *)). */
+#define TYPE_FLAG_STUB 8
+/* Set when a class has a constructor defined */
+#define TYPE_FLAG_HAS_CONSTRUCTOR 256
+/* Set when a class has a destructor defined */
+#define TYPE_FLAG_HAS_DESTRUCTOR 512
+/* Indicates that this type is a public baseclass of another class,
+ i.e. that all its public methods are available in the derived
+ class. */
+#define TYPE_FLAG_VIA_PUBLIC 1024
+/* Indicates that this type is a virtual baseclass of another class,
+ i.e. that if this class is inherited more than once by another
+ class, only one set of member variables will be included. */
+#define TYPE_FLAG_VIA_VIRTUAL 2048
+
+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 or method type, describes the type of the 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.
+ 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;
+ /* C++: also need a reference type. */
+ struct type *reference_type;
+ struct type **arg_types;
+
+ /* 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;
+
+/* Handling of pointers to members:
+ TYPE_MAIN_VARIANT is used for pointer and pointer
+ to member types. Normally it the value of the address of its
+ containing type. However, for pointers to members, we must be
+ able to allocate pointer to member types and look them up
+ from some place of reference.
+ NEXT_VARIANT is the next element in the chain. */
+ struct type *main_variant, *next_variant;
+
+ /* 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".
+
+ 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;
+
+ /* C++ */
+ int *private_field_bits;
+ int *protected_field_bits;
+
+ /* Number of methods described for this type */
+ short nfn_fields;
+ /* Number of base classes this type derives from. */
+ short n_baseclasses;
+
+ /* Number of methods described for this type plus all the
+ methods that it derives from. */
+ int nfn_fields_total;
+
+ /* 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. */
+ 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 0
+ /* The overloaded name */
+ char *name;
+#endif
+ /* The return value of the method */
+ struct type *type;
+ /* The argument list */
+ struct type **args;
+ /* The name after it has been processed */
+ char *physname;
+ /* If this is a virtual function, the offset into the vtbl-1,
+ else 0. */
+ int voffset;
+ } *fn_fields;
+
+ int *private_fn_field_bits;
+ int *protected_fn_field_bits;
+
+ } *fn_fieldlists;
+
+ unsigned char via_protected;
+ unsigned char via_public;
+
+ /* For types with virtual functions, VPTR_BASETYPE is the base class which
+ defined the virtual function table pointer. VPTR_FIELDNO is
+ the field number of that pointer in the structure.
+
+ For types that are pointer to member types, VPTR_BASETYPE
+ ifs the type that this pointer is a member of.
+
+ Unused otherwise. */
+ struct type *vptr_basetype;
+
+ int vptr_fieldno;
+
+ /* If this type has a base class, put it here.
+ If this type is a pointer type, the chain of member pointer
+ types goes here.
+ Unused otherwise.
+
+ Contrary to all maxims of C style and common sense, the baseclasses
+ are indexed from 1 to N_BASECLASSES rather than 0 to N_BASECLASSES-1
+ (i.e. BASECLASSES points to one *before* the first element of
+ the array). */
+ struct type **baseclasses;
+};
+
+/* 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;
+ /* A flag indicating whether or not the fucntion corresponding
+ to this block was compiled with gcc or not. If there is no
+ function corresponding to this block, this meaning of this flag
+ is undefined. (In practice it will be 1 if the block was created
+ while processing a file compiled with gcc and 0 when not). */
+ unsigned char gcc_compile_flag;
+ /* 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_REF_ARG, /* Value address is at spec'd position in */
+ /* arglist. */
+ LOC_REGPARM, /* Value is at spec'd position in register window */
+ 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;
+};
+
+struct partial_symbol
+{
+ /* Symbol name */
+ char *name;
+ /* Name space code. */
+ enum namespace namespace;
+ /* Address class (for info_symbols) */
+ enum address_class class;
+ /* Associated partial symbol table */
+ struct partial_symtab *pst;
+ /* Value (only used for static functions currently). Done this
+ way so that we can use the struct symbol macros.
+ Note that the address of a function is SYMBOL_VALUE (pst)
+ in a partial symbol table, but BLOCK_START (SYMBOL_BLOCK_VALUE (st))
+ in a symbol table. */
+ union
+ {
+ long value;
+ }
+ value;
+};
+
+/*
+ * Vectors of all partial symbols read in from file; actually declared
+ * and used in dbxread.c.
+ */
+extern struct psymbol_allocation_list {
+ struct partial_symbol *list, *next;
+ int size;
+} global_psymbols, static_psymbols;
+
+
+/* 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 */
+};
+
+/* 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.
+
+ Each item used to be an int; either minus a line number, or a
+ program counter. If it represents a line number, that is the line
+ described by the next program counter value. If it is positive, it
+ is the program counter at which the code for the next line starts. */
+
+struct linetable_entry
+{
+ int line;
+ CORE_ADDR pc;
+};
+
+struct linetable
+{
+ int nitems;
+ struct linetable_entry item[1];
+};
+
+/* All the information on one source file. */
+
+struct source
+{
+ char *name; /* Name of file */
+ struct linetable contents;
+};
diff --git a/gnu/usr.bin/gdb/symtab.c b/gnu/usr.bin/gdb/symtab.c
new file mode 100644
index 0000000..4e4bd8e
--- /dev/null
+++ b/gnu/usr.bin/gdb/symtab.c
@@ -0,0 +1,2473 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ *
+ * $Header: /a/cvs/386BSD/src/gnu/gdb/symtab.c,v 1.1 1993/06/29 09:47:40 nate Exp $;
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)symtab.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Symbol table lookup for the GNU debugger, GDB.
+ Copyright (C) 1986, 1987, 1988, 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. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+
+#include <obstack.h>
+#include <assert.h>
+
+char *index ();
+extern char *cplus_demangle ();
+extern struct value * value_of_this ();
+
+/* Allocate an obstack to hold objects that should be freed
+ when we load a new symbol table.
+ This includes the symbols made by dbxread
+ and the types that are not permanent. */
+
+struct obstack obstack1;
+
+struct obstack *symbol_obstack = &obstack1;
+
+/* This obstack will be used for partial_symbol objects. It can
+ probably actually be the same as the symbol_obstack above, but I'd
+ like to keep them seperate for now. If I want to later, I'll
+ replace one with the other. */
+
+struct obstack obstack2;
+
+struct obstack *psymbol_obstack = &obstack2;
+
+/* 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;
+#ifdef LONG_LONG
+struct type *builtin_type_long_long;
+#endif
+struct type *builtin_type_unsigned_char;
+struct type *builtin_type_unsigned_short;
+struct type *builtin_type_unsigned_int;
+struct type *builtin_type_unsigned_long;
+#ifdef LONG_LONG
+struct type *builtin_type_unsigned_long_long;
+#endif
+struct type *builtin_type_float;
+struct type *builtin_type_double;
+
+/* 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. */
+struct block *block_found;
+
+/* Functions */
+static int find_line_common ();
+int lookup_misc_func ();
+struct partial_symtab *lookup_partial_symtab ();
+struct symtab *psymtab_to_symtab ();
+static struct partial_symbol *lookup_partial_symbol ();
+
+/* 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 = index (name, '/');
+ register int len = strlen (name);
+
+ for (s = symtab_list; s; s = s->next)
+ if (!strcmp (name, s->filename))
+ return s;
+
+ for (ps = partial_symtab_list; ps; ps = ps->next)
+ if (!strcmp (name, ps->filename))
+ {
+ if (ps->readin)
+ fatal ("Internal: readin pst found when no symtab found.");
+ s = psymtab_to_symtab (ps);
+ return s;
+ }
+
+ if (!slash)
+ {
+ for (s = symtab_list; s; s = s->next)
+ {
+ int l = strlen (s->filename);
+
+ if (s->filename[l - len -1] == '/'
+ && !strcmp (s->filename + l - len, name))
+ return s;
+ }
+
+ for (ps = partial_symtab_list; ps; ps = ps->next)
+ {
+ int l = strlen (ps->filename);
+
+ if (ps->filename[l - len - 1] == '/'
+ && !strcmp (ps->filename + l - len, name))
+ {
+ if (ps->readin)
+ fatal ("Internal: readin pst found when no symtab found.");
+ s = psymtab_to_symtab (ps);
+ return s;
+ }
+ }
+ }
+ return 0;
+}
+
+/* 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;
+ register char *copy;
+
+ s = lookup_symtab_1 (name);
+ if (s) return s;
+
+ /* If name not found as specified, see if adding ".c" helps. */
+
+ copy = (char *) alloca (strlen (name) + 3);
+ strcpy (copy, name);
+ strcat (copy, ".c");
+ s = lookup_symtab_1 (copy);
+ if (s) return s;
+
+ /* We didn't find anything; die. */
+ return 0;
+}
+
+/* Lookup the partial symbol table of a source file named NAME. This
+ only returns true on an exact match (ie. this semantics are
+ different from lookup_symtab. */
+
+struct partial_symtab *
+lookup_partial_symtab (name)
+char *name;
+{
+ register struct partial_symtab *s;
+ register char *copy;
+
+ for (s = partial_symtab_list; s; s = s->next)
+ if (!strcmp (name, s->filename))
+ return s;
+
+ return 0;
+}
+
+/* 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 = lookup_symbol (name, block, VAR_NAMESPACE, 0);
+ if (sym == 0 || SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+ {
+ if (!strcmp (name, "int"))
+ return builtin_type_int;
+ if (!strcmp (name, "long"))
+ return builtin_type_long;
+ if (!strcmp (name, "short"))
+ return builtin_type_short;
+ if (!strcmp (name, "char"))
+ return builtin_type_char;
+ if (!strcmp (name, "float"))
+ return builtin_type_float;
+ if (!strcmp (name, "double"))
+ return builtin_type_double;
+ if (!strcmp (name, "void"))
+ return builtin_type_void;
+
+ if (noerr)
+ return 0;
+ error ("No type named %s.", name);
+ }
+ return SYMBOL_TYPE (sym);
+}
+
+struct type *
+lookup_unsigned_typename (name)
+ char *name;
+{
+ if (!strcmp (name, "int"))
+ return builtin_type_unsigned_int;
+ if (!strcmp (name, "long"))
+ return builtin_type_unsigned_long;
+ if (!strcmp (name, "short"))
+ return builtin_type_unsigned_short;
+ if (!strcmp (name, "char"))
+ return builtin_type_unsigned_char;
+ error ("No type named unsigned %s.", name);
+}
+
+/* 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
+ = lookup_symbol (name, block, STRUCT_NAMESPACE, 0);
+
+ if (sym == 0)
+ 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
+ = lookup_symbol (name, block, STRUCT_NAMESPACE, 0);
+
+ if (sym == 0)
+ 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
+ = lookup_symbol (name, block, STRUCT_NAMESPACE, 0);
+ if (sym == 0)
+ 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);
+}
+
+/* Given a type TYPE, lookup the type of the component of type named
+ NAME. */
+
+struct type *
+lookup_struct_elt_type (type, name)
+ struct type *type;
+ char *name;
+{
+ struct type *t;
+ int i;
+ char *errmsg;
+
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION)
+ {
+ terminal_ours ();
+ fflush (stdout);
+ fprintf (stderr, "Type ");
+ type_print (type, "", stderr, -1);
+ fprintf (stderr, " is not a structure or union type.\n");
+ return_to_top_level ();
+ }
+
+ for (i = TYPE_NFIELDS (type) - 1; i >= 0; i--)
+ if (!strcmp (TYPE_FIELD_NAME (type, i), name))
+ return TYPE_FIELD_TYPE (type, i);
+
+ terminal_ours ();
+ fflush (stdout);
+ fprintf (stderr, "Type ");
+ type_print (type, "", stderr, -1);
+ fprintf (stderr, " has no component named %s\n", name);
+ return_to_top_level ();
+}
+
+/* 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.
+
+ C++: use TYPE_MAIN_VARIANT and TYPE_CHAIN to keep pointer
+ to member types under control. */
+
+struct type *
+lookup_pointer_type (type)
+ struct type *type;
+{
+ register struct type *ptype = TYPE_POINTER_TYPE (type);
+ if (ptype) return TYPE_MAIN_VARIANT (ptype);
+
+ /* This is the first time anyone wanted a pointer to a TYPE. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ ptype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ ptype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ bzero (ptype, sizeof (struct type));
+ TYPE_MAIN_VARIANT (ptype) = ptype;
+ TYPE_TARGET_TYPE (ptype) = type;
+ TYPE_POINTER_TYPE (type) = ptype;
+ /* New type is permanent if type pointed to is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM;
+ /* We assume the machine has only one representation for pointers! */
+ TYPE_LENGTH (ptype) = sizeof (char *);
+ TYPE_CODE (ptype) = TYPE_CODE_PTR;
+ return ptype;
+}
+
+struct type *
+lookup_reference_type (type)
+ struct type *type;
+{
+ register struct type *rtype = TYPE_REFERENCE_TYPE (type);
+ if (rtype) return TYPE_MAIN_VARIANT (rtype);
+
+ /* This is the first time anyone wanted a pointer to a TYPE. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ rtype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ rtype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ bzero (rtype, sizeof (struct type));
+ TYPE_MAIN_VARIANT (rtype) = rtype;
+ TYPE_TARGET_TYPE (rtype) = type;
+ TYPE_REFERENCE_TYPE (type) = rtype;
+ /* New type is permanent if type pointed to is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (rtype) |= TYPE_FLAG_PERM;
+ /* We assume the machine has only one representation for pointers! */
+ TYPE_LENGTH (rtype) = sizeof (char *);
+ TYPE_CODE (rtype) = TYPE_CODE_REF;
+ return rtype;
+}
+
+
+/* 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, *domain;
+{
+ register struct type *mtype = TYPE_MAIN_VARIANT (type);
+ struct type *main_type;
+
+ main_type = mtype;
+ while (mtype)
+ {
+ if (TYPE_DOMAIN_TYPE (mtype) == domain)
+ return mtype;
+ mtype = TYPE_NEXT_VARIANT (mtype);
+ }
+
+ /* This is the first time anyone wanted this member type. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ mtype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ mtype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ bzero (mtype, sizeof (struct type));
+ if (main_type == 0)
+ main_type = mtype;
+ else
+ {
+ TYPE_NEXT_VARIANT (mtype) = TYPE_NEXT_VARIANT (main_type);
+ TYPE_NEXT_VARIANT (main_type) = mtype;
+ }
+ TYPE_MAIN_VARIANT (mtype) = main_type;
+ TYPE_TARGET_TYPE (mtype) = type;
+ TYPE_DOMAIN_TYPE (mtype) = domain;
+ /* New type is permanent if type pointed to is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (mtype) |= TYPE_FLAG_PERM;
+
+ /* In practice, this is never used. */
+ TYPE_LENGTH (mtype) = 1;
+ TYPE_CODE (mtype) = TYPE_CODE_MEMBER;
+
+#if 0
+ /* Now splice in the new member pointer type. */
+ if (main_type)
+ {
+ /* This type was not "smashed". */
+ TYPE_CHAIN (mtype) = TYPE_CHAIN (main_type);
+ TYPE_CHAIN (main_type) = mtype;
+ }
+#endif
+
+ return mtype;
+}
+
+struct type *
+lookup_method_type (type, domain, args)
+ struct type *type, *domain, **args;
+{
+ register struct type *mtype = TYPE_MAIN_VARIANT (type);
+ struct type *main_type;
+
+ main_type = mtype;
+ while (mtype)
+ {
+ if (TYPE_DOMAIN_TYPE (mtype) == domain)
+ {
+ struct type **t1 = args;
+ struct type **t2 = TYPE_ARG_TYPES (mtype);
+ if (t2)
+ {
+ int i;
+ for (i = 0; t1[i] != 0 && t1[i]->code != TYPE_CODE_VOID; i++)
+ if (t1[i] != t2[i])
+ break;
+ if (t1[i] == t2[i])
+ return mtype;
+ }
+ }
+ mtype = TYPE_NEXT_VARIANT (mtype);
+ }
+
+ /* This is the first time anyone wanted this member type. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ mtype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ mtype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ bzero (mtype, sizeof (struct type));
+ if (main_type == 0)
+ main_type = mtype;
+ else
+ {
+ TYPE_NEXT_VARIANT (mtype) = TYPE_NEXT_VARIANT (main_type);
+ TYPE_NEXT_VARIANT (main_type) = mtype;
+ }
+ TYPE_MAIN_VARIANT (mtype) = main_type;
+ TYPE_TARGET_TYPE (mtype) = type;
+ TYPE_DOMAIN_TYPE (mtype) = domain;
+ TYPE_ARG_TYPES (mtype) = args;
+ /* New type is permanent if type pointed to is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (mtype) |= TYPE_FLAG_PERM;
+
+ /* In practice, this is never used. */
+ TYPE_LENGTH (mtype) = 1;
+ TYPE_CODE (mtype) = TYPE_CODE_METHOD;
+
+#if 0
+ /* Now splice in the new member pointer type. */
+ if (main_type)
+ {
+ /* This type was not "smashed". */
+ TYPE_CHAIN (mtype) = TYPE_CHAIN (main_type);
+ TYPE_CHAIN (main_type) = mtype;
+ }
+#endif
+
+ return mtype;
+}
+
+/* Given a type TYPE, return a type which has offset OFFSET,
+ via_virtual VIA_VIRTUAL, and via_public VIA_PUBLIC.
+ May need to construct such a type if none exists. */
+struct type *
+lookup_basetype_type (type, offset, via_virtual, via_public)
+ struct type *type;
+ int offset;
+ int via_virtual, via_public;
+{
+ register struct type *btype = TYPE_MAIN_VARIANT (type);
+ struct type *main_type;
+
+ if (offset != 0)
+ {
+ printf ("Internal error: type offset non-zero in lookup_basetype_type");
+ offset = 0;
+ }
+
+ main_type = btype;
+ while (btype)
+ {
+ if (/* TYPE_OFFSET (btype) == offset
+ && */ TYPE_VIA_PUBLIC (btype) == via_public
+ && TYPE_VIA_VIRTUAL (btype) == via_virtual)
+ return btype;
+ btype = TYPE_NEXT_VARIANT (btype);
+ }
+
+ /* This is the first time anyone wanted this member type. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ btype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ btype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ if (main_type == 0)
+ {
+ main_type = btype;
+ bzero (btype, sizeof (struct type));
+ TYPE_MAIN_VARIANT (btype) = main_type;
+ }
+ else
+ {
+ bcopy (main_type, btype, sizeof (struct type));
+ TYPE_NEXT_VARIANT (main_type) = btype;
+ }
+/* TYPE_OFFSET (btype) = offset; */
+ if (via_public)
+ TYPE_FLAGS (btype) |= TYPE_FLAG_VIA_PUBLIC;
+ if (via_virtual)
+ TYPE_FLAGS (btype) |= TYPE_FLAG_VIA_VIRTUAL;
+ /* New type is permanent if type pointed to is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (btype) |= TYPE_FLAG_PERM;
+
+ /* In practice, this is never used. */
+ TYPE_LENGTH (btype) = 1;
+ TYPE_CODE (btype) = TYPE_CODE_STRUCT;
+
+ return btype;
+}
+
+/* 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;
+{
+ register struct type *ptype = TYPE_FUNCTION_TYPE (type);
+ if (ptype) return ptype;
+
+ /* This is the first time anyone wanted a function returning a TYPE. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ ptype = (struct type *) xmalloc (sizeof (struct type));
+ else
+ ptype = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+
+ bzero (ptype, sizeof (struct type));
+ TYPE_TARGET_TYPE (ptype) = type;
+ TYPE_FUNCTION_TYPE (type) = ptype;
+ /* New type is permanent if type returned is permanent. */
+ if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+ TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM;
+ TYPE_LENGTH (ptype) = 1;
+ TYPE_CODE (ptype) = TYPE_CODE_FUNC;
+ TYPE_NFIELDS (ptype) = 0;
+ return ptype;
+}
+
+/* Create an array type. Elements will be of type TYPE, and there will
+ be NUM of them.
+
+ Eventually this should be extended to take two more arguments which
+ specify the bounds of the array and the type of the index.
+ It should also be changed to be a "lookup" function, with the
+ appropriate data structures added to the type field.
+ Then read array type should call here. */
+
+struct type *
+create_array_type (element_type, number)
+ struct type *element_type;
+ int number;
+{
+ struct type *result_type = (struct type *)
+ obstack_alloc (symbol_obstack, sizeof (struct type));
+
+ bzero (result_type, sizeof (struct type));
+
+ TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
+ TYPE_TARGET_TYPE (result_type) = element_type;
+ TYPE_LENGTH (result_type) = number * TYPE_LENGTH (element_type);
+ TYPE_NFIELDS (result_type) = 1;
+ TYPE_FIELDS (result_type) =
+ (struct field *) obstack_alloc (symbol_obstack, sizeof (struct field));
+ TYPE_FIELD_TYPE (result_type, 0) = builtin_type_int;
+ TYPE_VPTR_FIELDNO (result_type) = -1;
+
+ return result_type;
+}
+
+
+/* Smash TYPE to be a type of pointers to TO_TYPE.
+ If TO_TYPE is not permanent and has no pointer-type yet,
+ record TYPE as its pointer-type. */
+
+void
+smash_to_pointer_type (type, to_type)
+ struct type *type, *to_type;
+{
+ int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM);
+
+ bzero (type, sizeof (struct type));
+ TYPE_TARGET_TYPE (type) = to_type;
+ /* We assume the machine has only one representation for pointers! */
+ TYPE_LENGTH (type) = sizeof (char *);
+ TYPE_CODE (type) = TYPE_CODE_PTR;
+
+ TYPE_MAIN_VARIANT (type) = type;
+
+ if (type_permanent)
+ TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
+
+ if (TYPE_POINTER_TYPE (to_type) == 0
+ && (!(TYPE_FLAGS (to_type) & TYPE_FLAG_PERM)
+ || type_permanent))
+ {
+ TYPE_POINTER_TYPE (to_type) = type;
+ }
+}
+
+/* Smash TYPE to be a type of members of DOMAIN with type TO_TYPE. */
+
+void
+smash_to_member_type (type, domain, to_type)
+ struct type *type, *domain, *to_type;
+{
+ bzero (type, sizeof (struct type));
+ TYPE_TARGET_TYPE (type) = to_type;
+ TYPE_DOMAIN_TYPE (type) = domain;
+
+ /* In practice, this is never needed. */
+ TYPE_LENGTH (type) = 1;
+ TYPE_CODE (type) = TYPE_CODE_MEMBER;
+
+ TYPE_MAIN_VARIANT (type) = lookup_member_type (domain, to_type);
+}
+
+/* Smash TYPE to be a type of method of DOMAIN with type TO_TYPE. */
+
+void
+smash_to_method_type (type, domain, to_type, args)
+ struct type *type, *domain, *to_type, **args;
+{
+ bzero (type, sizeof (struct type));
+ TYPE_TARGET_TYPE (type) = to_type;
+ TYPE_DOMAIN_TYPE (type) = domain;
+ TYPE_ARG_TYPES (type) = args;
+
+ /* In practice, this is never needed. */
+ TYPE_LENGTH (type) = 1;
+ TYPE_CODE (type) = TYPE_CODE_METHOD;
+
+ TYPE_MAIN_VARIANT (type) = lookup_method_type (domain, to_type, args);
+}
+
+/* Smash TYPE to be a type of reference to TO_TYPE.
+ If TO_TYPE is not permanent and has no pointer-type yet,
+ record TYPE as its pointer-type. */
+
+void
+smash_to_reference_type (type, to_type)
+ struct type *type, *to_type;
+{
+ int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM);
+
+ bzero (type, sizeof (struct type));
+ TYPE_TARGET_TYPE (type) = to_type;
+ /* We assume the machine has only one representation for pointers! */
+ TYPE_LENGTH (type) = sizeof (char *);
+ TYPE_CODE (type) = TYPE_CODE_REF;
+
+ TYPE_MAIN_VARIANT (type) = type;
+
+ if (type_permanent)
+ TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
+
+ if (TYPE_REFERENCE_TYPE (to_type) == 0
+ && (!(TYPE_FLAGS (to_type) & TYPE_FLAG_PERM)
+ || type_permanent))
+ {
+ TYPE_REFERENCE_TYPE (to_type) = type;
+ }
+}
+
+/* Smash TYPE to be a type of functions returning TO_TYPE.
+ If TO_TYPE is not permanent and has no function-type yet,
+ record TYPE as its function-type. */
+
+void
+smash_to_function_type (type, to_type)
+ struct type *type, *to_type;
+{
+ int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM);
+
+ bzero (type, sizeof (struct type));
+ TYPE_TARGET_TYPE (type) = to_type;
+ TYPE_LENGTH (type) = 1;
+ TYPE_CODE (type) = TYPE_CODE_FUNC;
+ TYPE_NFIELDS (type) = 0;
+
+ if (type_permanent)
+ TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
+
+ if (TYPE_FUNCTION_TYPE (to_type) == 0
+ && (!(TYPE_FLAGS (to_type) & TYPE_FLAG_PERM)
+ || type_permanent))
+ {
+ TYPE_FUNCTION_TYPE (to_type) = type;
+ }
+}
+
+/* Find which partial symtab on the partial_symtab_list contains
+ PC. Return 0 if none. */
+
+struct partial_symtab *
+find_pc_psymtab (pc)
+ register CORE_ADDR pc;
+{
+ register struct partial_symtab *ps;
+
+ for (ps = partial_symtab_list; ps; ps = ps->next)
+ if (pc >= ps->textlow && pc < ps->texthigh)
+ return ps;
+
+ return 0;
+}
+
+/* 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, *p;
+ int best_pc;
+
+ if (!psymtab)
+ psymtab = find_pc_psymtab (pc);
+ if (!psymtab)
+ return 0;
+
+ best_pc = psymtab->textlow - 1;
+
+ for (p = static_psymbols.list + psymtab->statics_offset;
+ (p - (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 (p)
+ && SYMBOL_VALUE (p) > best_pc)
+ {
+ best_pc = SYMBOL_VALUE (p);
+ best = p;
+ }
+ if (best_pc == psymtab->textlow - 1)
+ return 0;
+ return best;
+}
+
+
+static struct symbol *lookup_block_symbol ();
+
+/* 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.
+ 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.) */
+
+struct symbol *
+lookup_symbol (name, block, namespace, is_a_field_of_this)
+ char *name;
+ register struct block *block;
+ enum namespace namespace;
+ int *is_a_field_of_this;
+{
+ register int i, n;
+ register struct symbol *sym;
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register struct partial_symbol *psym;
+ struct blockvector *bv;
+
+ /* Search specified block and its superiors. */
+
+ while (block != 0)
+ {
+ sym = lookup_block_symbol (block, name, namespace);
+ if (sym)
+ {
+ block_found = block;
+ return sym;
+ }
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ /* 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;
+ return 0;
+ }
+ }
+
+ /* Now search all global blocks. Do the symtab's first, then
+ check the psymtab's */
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, 0);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (sym)
+ {
+ block_found = block;
+ return sym;
+ }
+ }
+
+ /* Check for the possibility of the symbol being a global function
+ that is stored on the misc function vector. Eventually, all
+ global symbols might be resolved in this way. */
+
+ if (namespace == VAR_NAMESPACE)
+ {
+ int index = lookup_misc_func (name);
+
+ if (index == -1)
+ { /* Look for a mangled C++ name for NAME. */
+ int name_len = strlen (name);
+ for (index = misc_function_count; --index >= 0; )
+ /* Assume orginal name is prefix of mangled name. */
+ if (!strncmp (misc_function_vector[index].name, name, name_len))
+ {
+ char *demangled =
+ cplus_demangle(misc_function_vector[index].name, -1);
+ if (demangled != NULL)
+ {
+ int cond = strcmp (demangled, name);
+ free (demangled);
+ if (!cond)
+ break;
+ }
+ }
+ /* Loop terminates on no match with index == -1. */
+ }
+
+ if (index != -1)
+ {
+ ps = find_pc_psymtab (misc_function_vector[index].address);
+ if (ps && !ps->readin)
+ {
+ s = psymtab_to_symtab (ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, 0);
+ sym = lookup_block_symbol (block, name, namespace);
+ /* sym == 0 if symbol was found in the psymtab but not
+ in the symtab.
+ Return 0 to use the misc_function 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:");
+ */
+
+ return sym;
+ }
+ }
+ }
+
+ if (psym = lookup_partial_symbol (name, 1, namespace))
+ {
+ ps = psym->pst;
+ s = psymtab_to_symtab(ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, 0);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (!sym)
+ fatal ("Internal: global symbol found in psymtab but not in symtab");
+ 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 */
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, 1);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (sym)
+ {
+ block_found = block;
+ return sym;
+ }
+ }
+
+ if (psym = lookup_partial_symbol(name, 0, namespace))
+ {
+ ps = psym->pst;
+ s = psymtab_to_symtab(ps);
+ bv = BLOCKVECTOR (s);
+ block = BLOCKVECTOR_BLOCK (bv, 1);
+ sym = lookup_block_symbol (block, name, namespace);
+ if (!sym)
+ fatal ("Internal: static symbol found in psymtab but not in symtab");
+ return sym;
+ }
+
+ 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 (name, global, namespace)
+ register char *name;
+ register int global;
+ register enum namespace namespace;
+{
+ register struct partial_symbol *start, *psym;
+ register struct partial_symbol *top, *bottom, *center;
+ register struct partial_symtab *pst;
+ register int length;
+
+ if (global)
+ {
+ start = global_psymbols.list;
+ length = global_psymbols.next - start;
+ }
+ else
+ {
+ start = static_psymbols.list;
+ length = static_psymbols.next - start;
+ }
+
+ if (!length)
+ return (struct partial_symbol *) 0;
+
+ /* Binary search. This search is guarranteed 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;
+
+ assert (center < top);
+
+ if (strcmp (SYMBOL_NAME (center), name) >= 0)
+ top = center;
+ else
+ bottom = center + 1;
+ }
+ assert (top == bottom);
+
+ while (strcmp (SYMBOL_NAME (top), name) == 0)
+ {
+ if (!top->pst->readin && SYMBOL_NAMESPACE (top) == namespace)
+ return top;
+ top ++;
+ }
+
+ return (struct partial_symbol *) 0;
+}
+
+/* Look for a symbol in block BLOCK. */
+
+static struct symbol *
+lookup_block_symbol (block, name, namespace)
+ register struct block *block;
+ char *name;
+ enum namespace namespace;
+{
+ register int bot, top, inc;
+ register struct symbol *sym, *parameter_sym;
+
+ top = BLOCK_NSYMS (block);
+ bot = 0;
+
+ /* If the blocks's symbols were sorted, start with a binary search. */
+
+ if (BLOCK_SHOULD_SORT (block))
+ {
+ /* First, 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 (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. dbxread.c is careful to make sure
+ that if one is a register then it comes first. */
+
+ 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)
+ return 0;
+ bot++;
+ }
+ return 0;
+ }
+
+ /* Here if block isn't sorted.
+ 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. */
+
+ parameter_sym = (struct symbol *) 0;
+ top = BLOCK_NSYMS (block);
+ inc = name[0];
+ while (bot < top)
+ {
+ sym = BLOCK_SYM (block, bot);
+ if (SYMBOL_NAME (sym)[0] == inc
+ && !strcmp (SYMBOL_NAME (sym), name)
+ && SYMBOL_NAMESPACE (sym) == namespace)
+ {
+ if (SYMBOL_CLASS (sym) == LOC_ARG
+ || SYMBOL_CLASS (sym) == LOC_REF_ARG
+ || SYMBOL_CLASS (sym) == LOC_REGPARM)
+ parameter_sym = sym;
+ else
+ return sym;
+ }
+ bot++;
+ }
+ return parameter_sym; /* Will be 0 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);
+}
+
+/* Subroutine of find_pc_line */
+
+struct symtab *
+find_pc_symtab (pc)
+ register CORE_ADDR pc;
+{
+ register struct block *b;
+ struct blockvector *bv;
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+
+ /* Search all symtabs for one whose file contains our pc */
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ bv = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bv, 0);
+ if (BLOCK_START (b) <= pc
+ && BLOCK_END (b) > pc)
+ break;
+ }
+
+ if (!s)
+ {
+ ps = find_pc_psymtab (pc);
+ if (ps && ps->readin)
+ fatal ("Internal error: pc in read in psymtab, but not in symtab.");
+
+ if (ps)
+ s = psymtab_to_symtab (ps);
+ }
+
+ return s;
+}
+
+/* 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. */
+
+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 value;
+ struct blockvector *bv;
+
+ /* Info on best line seen so far, and where it starts, and its file. */
+
+ int best_line = 0;
+ CORE_ADDR best_pc = 0;
+ 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. */
+ int alt_line = 0;
+ CORE_ADDR alt_pc = 0;
+ struct symtab *alt_symtab = 0;
+
+ /* Info on best line seen in this file. */
+
+ int prev_line;
+ CORE_ADDR prev_pc;
+
+ /* Info on first line of this file. */
+
+ int first_line;
+ CORE_ADDR first_pc;
+
+ /* 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 == 0)
+ {
+ value.symtab = 0;
+ value.line = 0;
+ value.pc = pc;
+ value.end = 0;
+ return value;
+ }
+
+ 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);
+ len = l->nitems;
+ prev_line = -1;
+ first_line = -1;
+ for (i = 0; i < len; i++)
+ {
+ item = &(l->item[i]);
+
+ if (first_line < 0)
+ {
+ first_line = item->line;
+ first_pc = item->pc;
+ }
+ /* Return the last line that did not start after PC. */
+ if (pc >= item->pc)
+ {
+ prev_line = item->line;
+ prev_pc = item->pc;
+ }
+ else
+ break;
+ }
+
+ /* 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_line >= 0 && prev_pc > best_pc)
+ {
+ best_pc = prev_pc;
+ best_line = prev_line;
+ best_symtab = s;
+ if (i < len)
+ best_end = item->pc;
+ else
+ best_end = 0;
+ }
+ /* 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 (first_line >= 0 && first_pc > pc
+ && (alt_pc == 0 || first_pc < alt_pc))
+ {
+ alt_pc = first_pc;
+ alt_line = first_line;
+ alt_symtab = s;
+ }
+ }
+ if (best_symtab == 0)
+ {
+ value.symtab = alt_symtab;
+ value.line = alt_line - 1;
+ value.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0));
+ value.end = alt_pc;
+ }
+ else
+ {
+ value.symtab = best_symtab;
+ value.line = best_line;
+ value.pc = best_pc;
+ value.end = (best_end ? best_end
+ : (alt_pc ? alt_pc
+ : BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0))));
+ }
+ return value;
+}
+
+/* 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;
+{
+ register struct linetable *l;
+ register int index;
+ int dummy;
+
+ if (symtab == 0)
+ return 0;
+ l = LINETABLE (symtab);
+ index = find_line_common(l, line, &dummy);
+ return index ? l->item[index].pc : 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 (symtab, thisline, startptr, endptr)
+ struct symtab *symtab;
+ int thisline;
+ CORE_ADDR *startptr, *endptr;
+{
+ register struct linetable *l;
+ register int index;
+ int exact_match; /* did we get an exact linenumber match */
+ register CORE_ADDR prev_pc;
+ CORE_ADDR last_pc;
+
+ if (symtab == 0)
+ return 0;
+
+ l = LINETABLE (symtab);
+ index = find_line_common (l, thisline, &exact_match);
+ if (index)
+ {
+ *startptr = l->item[index].pc;
+ /* If we have not seen an entry for the specified line,
+ assume that means the specified line has zero bytes. */
+ if (!exact_match || index == l->nitems-1)
+ *endptr = *startptr;
+ else
+ /* Perhaps the following entry is for the following line.
+ It's worth a try. */
+ if (l->item[index+1].line == thisline + 1)
+ *endptr = l->item[index+1].pc;
+ else
+ *endptr = find_line_pc (symtab, thisline+1);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* 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 0 if none is found. The value is never zero is 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 = 0;
+ int best = 0;
+
+ int nextline = -1;
+
+ if (lineno <= 0)
+ return 0;
+
+ len = l->nitems;
+ for (i = 0; i < len; i++)
+ {
+ register struct linetable_entry *item = &(l->item[i]);
+
+ if (item->line == lineno)
+ {
+ *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;
+}
+
+/* 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.
+ FILE:FUNCTION -- likewise, but prefer functions in that file.
+ *EXPR -- line in which address EXPR appears.
+
+ FUNCTION may be an undebuggable function found in misc_function_vector.
+
+ 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.
+
+ 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. */
+
+struct symtabs_and_lines
+decode_line_1 (argptr, funfirstline, default_symtab, default_line)
+ char **argptr;
+ int funfirstline;
+ struct symtab *default_symtab;
+ int default_line;
+{
+ struct symtabs_and_lines decode_line_2 ();
+ struct symtabs_and_lines values;
+ struct symtab_and_line value;
+ register char *p, *p1;
+ register struct symtab *s;
+ register struct symbol *sym;
+ register CORE_ADDR pc;
+ register int i;
+ char *copy;
+ struct symbol *sym_class;
+ char *class_name, *method_name, *phys_name;
+ int method_counter;
+ int i1;
+ struct symbol **sym_arr;
+ struct type *t, *field;
+ char **physnames;
+
+ /* Defaults have defaults. */
+
+ if (default_symtab == 0)
+ {
+ default_symtab = current_source_symtab;
+ default_line = current_source_line;
+ }
+
+ /* See if arg is *PC */
+
+ if (**argptr == '*')
+ {
+ (*argptr)++;
+ pc = parse_and_eval_address_1 (argptr);
+ values.sals = (struct symtab_and_line *)
+ malloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ values.sals[0] = find_pc_line (pc, 0);
+ values.sals[0].pc = pc;
+ return values;
+ }
+
+ /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */
+
+ s = 0;
+
+ for (p = *argptr; *p; p++)
+ {
+ if (p[0] == ':' || p[0] == ' ' || p[0] == '\t')
+ break;
+ }
+ while (p[0] == ' ' || p[0] == '\t') p++;
+
+ if (p[0] == ':')
+ {
+
+ /* C++ */
+ if (p[1] ==':')
+ {
+ /* Extract the class name. */
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ') --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ bcopy (*argptr, copy, 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);
+
+ 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 whitespace). */
+ p = *argptr;
+ while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p !=':') p++;
+ copy = (char *) alloca (p - *argptr + 1);
+ bcopy (*argptr, copy, p - *argptr);
+ copy[p - *argptr] = '\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*));
+ physnames = (char **) alloca (TYPE_NFN_FIELDS_TOTAL (t) * sizeof(char*));
+
+ if (destructor_name_p (copy, t))
+ {
+ /* destructors are a special case. */
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, 0);
+ int len = TYPE_FN_FIELDLIST_LENGTH (t, 0) - 1;
+ phys_name = TYPE_FN_FIELD_PHYSNAME (f, len);
+ physnames[i1] = (char *)alloca (strlen (phys_name) + 1);
+ strcpy (physnames[i1], phys_name);
+ sym_arr[i1] = lookup_symbol (phys_name, SYMBOL_BLOCK_VALUE (sym_class), VAR_NAMESPACE, 0);
+ if (sym_arr[i1]) i1++;
+ }
+ else while (t)
+ {
+ class_name = TYPE_NAME (t);
+ /* Ignore this class if it doesn't have a name.
+ This prevents core dumps, but is just a workaround
+ because we might not find the function in
+ certain cases, such as
+ struct D {virtual int f();}
+ struct C : D {virtual int g();}
+ (in this case g++ 1.35.1- does not put out a name
+ for D as such, it defines type 19 (for example) in
+ the same stab as C, and then does a
+ .stabs "D:T19" and a .stabs "D:t19".
+ Thus
+ "break C::f" should not be looking for field f in
+ the class named D,
+ but just for the field f in the baseclasses of C
+ (no matter what their names).
+
+ However, I don't know how to replace the code below
+ that depends on knowing the name of D. */
+ if (class_name)
+ {
+ /* We just want the class name. In the context
+ of C++, stripping off "struct " is always
+ sensible. */
+ if (strncmp("struct ", class_name, 7) == 0)
+ class_name += 7;
+ if (strncmp("union ", class_name, 6) == 0)
+ class_name += 6;
+
+ sym_class = lookup_symbol (class_name, 0, STRUCT_NAMESPACE, 0);
+ for (method_counter = TYPE_NFN_FIELDS (SYMBOL_TYPE (sym_class)) - 1;
+ method_counter >= 0;
+ --method_counter)
+ {
+ int field_counter;
+ struct fn_field *f =
+ TYPE_FN_FIELDLIST1 (SYMBOL_TYPE (sym_class), method_counter);
+
+ method_name = TYPE_FN_FIELDLIST_NAME (SYMBOL_TYPE (sym_class), method_counter);
+ if (!strcmp (copy, method_name))
+ /* Find all the fields with that name. */
+ for (field_counter = TYPE_FN_FIELDLIST_LENGTH (SYMBOL_TYPE (sym_class), method_counter) - 1;
+ field_counter >= 0;
+ --field_counter)
+ {
+ phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
+ physnames[i1] = (char*) alloca (strlen (phys_name) + 1);
+ strcpy (physnames[i1], phys_name);
+ sym_arr[i1] = lookup_symbol (phys_name, SYMBOL_BLOCK_VALUE (sym_class), VAR_NAMESPACE, 0);
+ if (sym_arr[i1]) i1++;
+ }
+ }
+ }
+ if (TYPE_N_BASECLASSES (t))
+ t = TYPE_BASECLASS(t, 1);
+ else
+ break;
+ }
+
+ if (i1 == 1)
+ {
+ /* There is exactly one field with that name. */
+ sym = sym_arr[0];
+
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ /* Arg is the name of a function */
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (pc);
+ values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ values.sals[0] = find_pc_line (pc, 0);
+ values.sals[0].pc = (values.sals[0].end && values.sals[0].pc != pc) ? values.sals[0].end : pc;
+ }
+ 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 (argptr, sym_arr, physnames,
+ i1, funfirstline);
+ }
+ else
+ error ("that class does not have any method named %s",copy);
+ }
+ else
+ error("no class, struct, or union named %s", copy );
+ }
+ /* end of C++ */
+
+
+ /* Extract the file name. */
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ') --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ bcopy (*argptr, copy, p - *argptr);
+ copy[p - *argptr] = 0;
+
+ /* Find that file's data. */
+ s = lookup_symtab (copy);
+ if (s == 0)
+ {
+ if (symtab_list == 0 && partial_symtab_list == 0)
+ error ("No symbol table is loaded. Use the \"symbol-file\" command.");
+ 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) */
+
+ p = *argptr;
+ if (*p == '-' || *p == '+') p++;
+ while (*p >= '0' && *p <= '9')
+ p++;
+
+ if (p != *argptr && (*p == 0 || *p == ' ' || *p == '\t' || *p == ','))
+ {
+ /* We found a token consisting of all digits -- at least one digit. */
+ enum sign {none, plus, minus} sign = none;
+
+ /* This is where we need to make sure that we have good defaults.
+ We must guarrantee 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)
+ {
+ if (symtab_list == 0 && partial_symtab_list == 0)
+ error ("No symbol table is loaded. Use the \"symbol-file\" command.");
+ 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)++;
+ value.line = atoi (*argptr);
+ switch (sign)
+ {
+ case plus:
+ if (p == *argptr)
+ value.line = 5;
+ if (s == 0)
+ value.line = default_line + value.line;
+ break;
+ case minus:
+ if (p == *argptr)
+ value.line = 15;
+ if (s == 0)
+ value.line = default_line - value.line;
+ else
+ value.line = 1;
+ break;
+ }
+
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+ if (s == 0)
+ s = default_symtab;
+ value.symtab = s;
+ value.pc = 0;
+ values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line));
+ values.sals[0] = value;
+ values.nelts = 1;
+ return values;
+ }
+
+ /* Arg token is not digits => try it as a function name
+ Find the next token (everything up to end or next whitespace). */
+ p = *argptr;
+ while (*p && *p != ' ' && *p != '\t' && *p != ',') p++;
+ copy = (char *) alloca (p - *argptr + 1);
+ bcopy (*argptr, copy, p - *argptr);
+ copy[p - *argptr] = 0;
+ while (*p == ' ' || *p == '\t') p++;
+ *argptr = p;
+
+ /* Look up that token as a function.
+ If file specified, use that file's per-file block to start with. */
+
+ if (s == 0)
+ /* use current file as default if none is specified. */
+ s = default_symtab;
+
+ sym = lookup_symbol (copy, s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1) : 0,
+ VAR_NAMESPACE, 0);
+
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ /* Arg is the name of a function */
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (pc);
+ value = find_pc_line (pc, 0);
+#ifdef PROLOGUE_FIRSTLINE_OVERLAP
+ /* Convex: no need to suppress code on first line, if any */
+ value.pc = pc;
+#else
+ value.pc = (value.end && value.pc != pc) ? value.end : pc;
+#endif
+ values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line));
+ values.sals[0] = value;
+ values.nelts = 1;
+ return values;
+ }
+
+ if (sym)
+ error ("%s is not a function.", copy);
+
+ if (symtab_list == 0 && partial_symtab_list == 0)
+ error ("No symbol table is loaded. Use the \"symbol-file\" command.");
+
+ if ((i = lookup_misc_func (copy)) >= 0)
+ {
+ value.symtab = 0;
+ value.line = 0;
+ value.pc = misc_function_vector[i].address + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (value.pc);
+ values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line));
+ values.sals[0] = value;
+ values.nelts = 1;
+ return values;
+ }
+
+ error ("Function %s not defined.", copy);
+}
+
+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);
+ if (*string)
+ error ("Junk at end of line specification: %s", string);
+ return sals;
+}
+
+/* Given a list of NELTS symbols in sym_arr (with corresponding
+ mangled names in physnames), return a list of lines to operate on
+ (ask user if necessary). */
+struct symtabs_and_lines
+decode_line_2 (argptr, sym_arr, physnames, nelts, funfirstline)
+ char **argptr;
+ struct symbol *sym_arr[];
+ char *physnames[];
+ int nelts;
+ int funfirstline;
+{
+ char *getenv();
+ struct symtabs_and_lines values, return_values;
+ register CORE_ADDR pc;
+ char *args, *arg1, *command_line_input ();
+ int i;
+ char *prompt;
+
+ values.sals = (struct symtab_and_line *) alloca (nelts * sizeof(struct symtab_and_line));
+ return_values.sals = (struct symtab_and_line *) malloc (nelts * sizeof(struct symtab_and_line));
+
+ i = 0;
+ printf("[0] cancel\n[1] all\n");
+ while (i < nelts)
+ {
+ if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK)
+ {
+ /* Arg is the name of a function */
+ pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym_arr[i]))
+ + FUNCTION_START_OFFSET;
+ if (funfirstline)
+ SKIP_PROLOGUE (pc);
+ values.sals[i] = find_pc_line (pc, 0);
+ values.sals[i].pc = (values.sals[i].end && values.sals[i].pc != pc) ? values.sals[i].end : pc;
+ printf("[%d] file:%s; line number:%d\n",
+ (i+2), values.sals[i].symtab->filename, values.sals[i].line);
+ }
+ else printf ("?HERE\n");
+ i++;
+ }
+
+ if ((prompt = getenv ("PS2")) == NULL)
+ {
+ prompt = ">";
+ }
+ printf("%s ",prompt);
+ fflush(stdout);
+
+ args = command_line_input (0, 0);
+
+ if (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)
+ {
+ bcopy (values.sals, return_values.sals, (nelts * sizeof(struct symtab_and_line)));
+ return_values.nelts = nelts;
+ return return_values;
+ }
+
+ if (num > nelts + 2)
+ {
+ printf ("No choice number %d.\n", num);
+ }
+ else
+ {
+ num -= 2;
+ if (values.sals[num].pc)
+ {
+ return_values.sals[i++] = values.sals[num];
+ values.sals[num].pc = 0;
+ }
+ else
+ {
+ printf ("duplicate request for %d ignored.\n", num);
+ }
+ }
+
+ args = arg1;
+ while (*args == ' ' || *args == '\t') args++;
+ }
+ return_values.nelts = i;
+ return return_values;
+}
+
+/* hash a symbol ("hashpjw" from Aho, Sethi & Ullman, p.436) */
+
+int
+hash_symbol(str)
+ register char *str;
+{
+ register unsigned int h = 0, g;
+ register unsigned char c;
+
+ while (c = *(unsigned char *)str++) {
+ h = (h << 4) + c;
+ if (g = h & 0xf0000000) {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ return ((int)h);
+}
+
+/* Return the index of misc function named NAME. */
+
+int
+lookup_misc_func (name)
+ register char *name;
+{
+ register int i = hash_symbol(name) & (MISC_FUNC_HASH_SIZE - 1);
+
+ if (misc_function_vector == 0)
+ error("No symbol file");
+
+ i = misc_function_hash_tab[i];
+ while (i >= 0)
+ {
+ if (strcmp(misc_function_vector[i].name, name) == 0)
+ break;
+ i = misc_function_vector[i].next;
+ }
+ return (i);
+}
+
+/*
+ * Slave routine for sources_info. Force line breaks at ,'s.
+ */
+static void
+output_source_filename (name, next)
+char *name;
+int next;
+{
+ static int column = 0;
+
+ if (column != 0 && column + strlen (name) >= 70)
+ {
+ printf_filtered ("\n");
+ column = 0;
+ }
+ else if (column != 0)
+ {
+ printf_filtered (" ");
+ column++;
+ }
+ printf_filtered ("%s", name);
+ column += strlen (name);
+ if (next)
+ {
+ printf_filtered (",");
+ column++;
+ }
+
+ if (!next) column = 0;
+}
+
+static void
+sources_info ()
+{
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register int column = 0;
+
+ if (symtab_list == 0 && partial_symtab_list == 0)
+ {
+ printf ("No symbol table is loaded.\n");
+ return;
+ }
+
+ printf_filtered ("Source files for which symbols have been read in:\n\n");
+
+ for (s = symtab_list; s; s = s->next)
+ output_source_filename (s->filename, s->next);
+ printf_filtered ("\n\n");
+
+ printf_filtered ("Source files for which symbols will be read in on demand:\n\n");
+
+ for (ps = partial_symtab_list; ps; ps = ps->next)
+ if (!ps->readin)
+ output_source_filename (ps->filename, ps->next);
+ printf_filtered ("\n");
+}
+
+/* List all symbols (if REGEXP is 0) or all symbols matching REGEXP.
+ If CLASS is zero, list all symbols except functions and type names.
+ If CLASS is 1, list only functions.
+ If CLASS is 2, list only type names. */
+
+static void sort_block_syms ();
+
+static void
+list_symbols (regexp, class)
+ char *regexp;
+ int class;
+{
+ 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, *bound;
+ char *val;
+ static char *classnames[]
+ = {"variable", "function", "type", "method"};
+ int print_count = 0;
+ int found_in_file = 0;
+
+ if (regexp)
+ if (val = (char *) re_comp (regexp))
+ error ("Invalid regexp: %s", val);
+
+ /* Search through the partial_symtab_list *first* for all symbols
+ matching the regexp. That way we don't have to reproduce all of
+ the machinery below. */
+ for (psym = global_psymbols.list, bound = global_psymbols.next; ;
+ psym = static_psymbols.list, bound = static_psymbols.next)
+ {
+ for (; psym < bound; ++psym)
+ {
+ if (psym->pst->readin)
+ continue;
+
+ QUIT;
+ /* If it would match (logic taken from loop below)
+ load the file and go on to the next one */
+ if ((regexp == 0 || re_exec (SYMBOL_NAME (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(psym->pst);
+ }
+ if (psym == static_psymbols.next)
+ break;
+ }
+
+ /* Printout here so as to get after the "Reading in symbols"
+ messages which will be generated above. */
+ printf_filtered (regexp
+ ? "All %ss matching regular expression \"%s\":\n"
+ : "All defined %ss:\n",
+ classnames[class],
+ regexp);
+
+ /* Here, *if* the class is correct (function only, right now), we
+ should search through the misc function vector for symbols that
+ match and call find_pc_psymtab on them. If find_pc_psymtab returns
+ 0, don't worry about it (already read in or no debugging info). */
+
+ if (class == 1)
+ {
+ for (i = 0; i < misc_function_count; i++)
+ if (regexp == 0 || re_exec (misc_function_vector[i].name))
+ {
+ ps = find_pc_psymtab (misc_function_vector[i].address);
+ if (ps && !ps->readin)
+ psymtab_to_symtab (ps);
+ }
+ }
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ 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 = 0; i < 2; 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 == 0 || re_exec (SYMBOL_NAME (sym)))
+ && ((class == 0 && SYMBOL_CLASS (sym) != LOC_TYPEDEF
+ && SYMBOL_CLASS (sym) != LOC_BLOCK)
+ || (class == 1 && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ || (class == 2 && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+ || (class == 3 && SYMBOL_CLASS (sym) == LOC_BLOCK)))
+ {
+ if (!found_in_file)
+ {
+ printf_filtered ("\nFile %s:\n", s->filename);
+ print_count += 2;
+ }
+ found_in_file = 1;
+ if (class != 2 && i == 1)
+ printf_filtered ("static ");
+ if (class == 2
+ && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE)
+ printf_filtered ("typedef ");
+
+ if (class < 3)
+ {
+ type_print (SYMBOL_TYPE (sym),
+ (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+ ? "" : SYMBOL_NAME (sym)),
+ stdout, 0);
+
+ if (class == 2
+ && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE
+ && (TYPE_NAME ((SYMBOL_TYPE (sym))) == 0
+ || 0 != strcmp (TYPE_NAME ((SYMBOL_TYPE (sym))),
+ SYMBOL_NAME (sym))))
+ printf_filtered (" %s", SYMBOL_NAME (sym));
+
+ printf_filtered (";\n");
+ }
+ else
+ {
+# if 0
+ char buf[1024];
+ type_print_base (TYPE_FN_FIELD_TYPE(t, i), stdout, 0, 0);
+ type_print_varspec_prefix (TYPE_FN_FIELD_TYPE(t, i), stdout, 0);
+ sprintf (buf, " %s::", TYPE_NAME (t));
+ type_print_method_args (TYPE_FN_FIELD_ARGS (t, i), buf, name, stdout);
+# endif
+ }
+ }
+ }
+ }
+ prev_bv = bv;
+ }
+}
+
+static void
+variables_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 0);
+}
+
+static void
+functions_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 1);
+}
+
+static void
+types_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 2);
+}
+
+#if 0
+/* Tiemann says: "info methods was never implemented." */
+static void
+methods_info (regexp)
+ char *regexp;
+{
+ list_symbols (regexp, 3);
+}
+#endif /* 0 */
+
+/* Call sort_block_syms to sort alphabetically the symbols of one block. */
+
+static int
+compare_symbols (s1, s2)
+ struct symbol **s1, **s2;
+{
+ /* Names that are less should come first. */
+ register int namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2));
+ if (namediff != 0) return namediff;
+ /* For symbols of the same name, registers should come first. */
+ return ((SYMBOL_CLASS (*s2) == LOC_REGISTER)
+ - (SYMBOL_CLASS (*s1) == LOC_REGISTER));
+}
+
+static void
+sort_block_syms (b)
+ register struct block *b;
+{
+ qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
+ sizeof (struct symbol *), compare_symbols);
+}
+
+/* Initialize the standard C scalar types. */
+
+static
+struct type *
+init_type (code, length, uns, name)
+ enum type_code code;
+ int length, uns;
+ char *name;
+{
+ register struct type *type;
+
+ type = (struct type *) xmalloc (sizeof (struct type));
+ bzero (type, sizeof *type);
+ TYPE_MAIN_VARIANT (type) = type;
+ TYPE_CODE (type) = code;
+ TYPE_LENGTH (type) = length;
+ TYPE_FLAGS (type) = uns ? TYPE_FLAG_UNSIGNED : 0;
+ TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
+ TYPE_NFIELDS (type) = 0;
+ TYPE_NAME (type) = name;
+
+ /* C++ fancies. */
+ TYPE_NFN_FIELDS (type) = 0;
+ TYPE_N_BASECLASSES (type) = 0;
+ TYPE_BASECLASSES (type) = 0;
+ return type;
+}
+
+/* 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 a->startaddr >= b->startaddr && a->endaddr <= b->endaddr;
+}
+
+
+/* Helper routine for make_symbol_completion_list. */
+
+int return_val_size, return_val_index;
+char **return_val;
+
+void
+completion_list_add_symbol (symname)
+ char *symname;
+{
+ if (return_val_index + 3 > return_val_size)
+ return_val =
+ (char **)xrealloc (return_val,
+ (return_val_size *= 2) * sizeof (char *));
+
+ return_val[return_val_index] =
+ (char *)xmalloc (1 + strlen (symname));
+
+ strcpy (return_val[return_val_index], symname);
+
+ return_val[++return_val_index] = (char *)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)
+ char *text;
+{
+ register struct symtab *s;
+ register struct partial_symtab *ps;
+ register struct blockvector *bv;
+ struct blockvector *prev_bv = 0;
+ register struct block *b, *surrounding_static_block;
+ extern struct block *get_selected_block ();
+ register int i, j;
+ register struct symbol *sym;
+ struct partial_symbol *psym;
+
+ int text_len = strlen (text);
+ return_val_size = 100;
+ return_val_index = 0;
+ return_val =
+ (char **)xmalloc ((1 + return_val_size) *sizeof (char *));
+ return_val[0] = (char *)NULL;
+
+ /* Look through the partial symtabs for all symbols which begin
+ by matching TEXT. Add each one that you find to the list. */
+
+ for (ps = partial_symtab_list; ps; ps = ps->next)
+ {
+ /* If the psymtab's been read in we'll get it when we search
+ through the blockvector. */
+ if (ps->readin) continue;
+
+ for (psym = global_psymbols.list + ps->globals_offset;
+ psym < (global_psymbols.list + ps->globals_offset
+ + ps->n_global_syms);
+ psym++)
+ {
+ QUIT; /* If interrupted, then quit. */
+ if ((strncmp (SYMBOL_NAME (psym), text, text_len) == 0))
+ completion_list_add_symbol (SYMBOL_NAME (psym));
+ }
+
+ for (psym = static_psymbols.list + ps->statics_offset;
+ psym < (static_psymbols.list + ps->statics_offset
+ + ps->n_static_syms);
+ psym++)
+ {
+ QUIT;
+ if ((strncmp (SYMBOL_NAME (psym), text, text_len) == 0))
+ completion_list_add_symbol (SYMBOL_NAME (psym));
+ }
+ }
+
+ /* At this point scan through the misc function vector 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). */
+
+ for (i = 0; i < misc_function_count; i++)
+ if (!strncmp (text, misc_function_vector[i].name, text_len))
+ completion_list_add_symbol (misc_function_vector[i].name);
+
+ /* Search upwards from currently selected frame (so that we can
+ complete on local vars. */
+ for (b = get_selected_block (); b; 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++)
+ {
+ register struct symbol *sym = BLOCK_SYM (b, i);
+
+ if (!strncmp (SYMBOL_NAME (sym), text, text_len))
+ completion_list_add_symbol (SYMBOL_NAME (sym));
+
+ 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 = 0; j < TYPE_NFIELDS (t); j++)
+ if (TYPE_FIELD_NAME (t, j) &&
+ !strncmp (TYPE_FIELD_NAME (t, j), text, text_len))
+ completion_list_add_symbol (TYPE_FIELD_NAME (t, j));
+ }
+ }
+ }
+
+ /* Go through the symtabs and check the externs and statics for
+ symbols which match. */
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ struct block *b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 0);
+
+ for (i = 0; i < BLOCK_NSYMS (b); i++)
+ if (!strncmp (SYMBOL_NAME (BLOCK_SYM (b, i)), text, text_len))
+ completion_list_add_symbol (SYMBOL_NAME (BLOCK_SYM (b, i)));
+ }
+
+ for (s = symtab_list; s; s = s->next)
+ {
+ struct block *b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1);
+
+ /* Don't do this block twice. */
+ if (b == surrounding_static_block) continue;
+
+ for (i = 0; i < BLOCK_NSYMS (b); i++)
+ if (!strncmp (SYMBOL_NAME (BLOCK_SYM (b, i)), text, text_len))
+ completion_list_add_symbol (SYMBOL_NAME (BLOCK_SYM (b, i)));
+ }
+
+ return (return_val);
+}
+
+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.");
+ add_info ("types", types_info,
+ "All types 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 ommited, it is assumed to be the current scope.\n\
+If the first REGEXP is ommited, then all methods matching the second REGEXP\n\
+are listed.");
+#endif
+ add_info ("sources", sources_info,
+ "Source files in the program.");
+
+ obstack_init (symbol_obstack);
+ obstack_init (psymbol_obstack);
+
+ builtin_type_void = init_type (TYPE_CODE_VOID, 1, 0, "void");
+
+ builtin_type_float = init_type (TYPE_CODE_FLT, sizeof (float), 0, "float");
+ builtin_type_double = init_type (TYPE_CODE_FLT, sizeof (double), 0, "double");
+
+ builtin_type_char = init_type (TYPE_CODE_INT, sizeof (char), 0, "char");
+ builtin_type_short = init_type (TYPE_CODE_INT, sizeof (short), 0, "short");
+ builtin_type_long = init_type (TYPE_CODE_INT, sizeof (long), 0, "long");
+ builtin_type_int = init_type (TYPE_CODE_INT, sizeof (int), 0, "int");
+
+ builtin_type_unsigned_char = init_type (TYPE_CODE_INT, sizeof (char), 1, "unsigned char");
+ builtin_type_unsigned_short = init_type (TYPE_CODE_INT, sizeof (short), 1, "unsigned short");
+ builtin_type_unsigned_long = init_type (TYPE_CODE_INT, sizeof (long), 1, "unsigned long");
+ builtin_type_unsigned_int = init_type (TYPE_CODE_INT, sizeof (int), 1, "unsigned int");
+#ifdef LONG_LONG
+ builtin_type_long_long =
+ init_type (TYPE_CODE_INT, sizeof (long long), 0, "long long");
+ builtin_type_unsigned_long_long =
+ init_type (TYPE_CODE_INT, sizeof (long long), 1, "unsigned long long");
+#endif
+}
+
diff --git a/gnu/usr.bin/gdb/symtab.h b/gnu/usr.bin/gdb/symtab.h
new file mode 100644
index 0000000..fefed60
--- /dev/null
+++ b/gnu/usr.bin/gdb/symtab.h
@@ -0,0 +1,384 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ *
+ * @(#)symtab.h 6.3 (Berkeley) 5/8/91
+ */
+
+/* Symbol table definitions for GDB.
+ Copyright (C) 1986, 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. */
+
+#include <obstack.h>
+
+/* An obstack to hold objects that should be freed
+ when we load a new symbol table.
+ This includes the symbols made by dbxread
+ and the types that are not permanent. */
+
+extern struct obstack *symbol_obstack;
+extern struct obstack *psymbol_obstack;
+
+/* Some definitions and declarations to go with use of obstacks. */
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+extern char *xmalloc ();
+extern void free ();
+
+/* gdb can know one or several symbol tables at the same time;
+ the ultimate intent is to have one for each separately-compiled module.
+ Each such symbol table is recorded by a struct symtab, and they
+ are all chained together. */
+
+/* In addition, gdb can record any number of miscellaneous undebuggable
+ functions' addresses. In a system that appends _ to function names,
+ the _'s are removed from the names stored in this table. */
+
+/* Actually, the misc function list is used to store *all* of the
+ global symbols (text, data, bss, and abs). It is sometimes used
+ to figure out what symtabs to read in. The "type" field appears
+ never to be used. */
+
+enum misc_function_type {mf_unknown = 0, mf_text, mf_data, mf_bss, mf_abs};
+
+struct misc_function
+{
+ char *name;
+ CORE_ADDR address;
+ int next; /* index of next in this hash bucket */
+ unsigned char type; /* Really enum misc_function_type. */
+};
+
+/* Address and length of the vector recording all misc function names/addresses. */
+
+struct misc_function *misc_function_vector;
+int misc_function_count;
+#define MISC_FUNC_HASH_SIZE (2048)
+int misc_function_hash_tab[MISC_FUNC_HASH_SIZE];
+
+#include "symseg.h"
+
+/* Each source file 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. */
+ struct blockvector *blockvector;
+ /* Table mapping core addresses to line numbers for this file. */
+ struct linetable *linetable;
+ /* Vector containing all types defined for this symtab. */
+ struct typevector *typevector;
+ /* Name of this source file. */
+ char *filename;
+ /* 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. */
+ enum free_code {free_nothing, free_contents, free_linetable}
+ free_code;
+ /* Pointer to one block of storage to be freed, if nonzero. */
+ char *free_ptr;
+ /* Total number of lines found in source file. */
+ int nlines;
+ /* Array mapping line number to character position. */
+ int *line_charpos;
+ /* Language of this source file. */
+ enum language language;
+ /* String of version information. May be zero. */
+ char *version;
+ /* String of compilation information. May be zero. */
+ char *compilation;
+ /* Offset within loader symbol table
+ of first local symbol for this file. */
+ int ldsymoff;
+ /* Full name of file as found by searching the source path.
+ 0 if not yet known. */
+ char *fullname;
+ };
+
+/*
+ * 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.
+ */
+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;
+ /* Offset within loader 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 files symbols
+ If ldsymlen is 0, the only reason for this things existence is
+ the dependency list below. Nothing else will happen when it is
+ read in. */
+ int ldsymoff, ldsymlen;
+ /* Range of text addresses covered by this file; texthigh is the
+ beginning of the next section. */
+ int textlow, texthigh;
+ /* Non-zero if the symtab corresponding to this psymtab has been
+ readin */
+ unsigned char readin;
+ /* Array of pointers to all of the partial_symtab s which this one
+ depends one. Since this array can only be set to previous or
+ the current (?) psymtab, this dependency tree is guarranteed not
+ to have any loops. */
+ 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 ps_globals */
+ int globals_offset, 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). */
+ int statics_offset, n_static_syms;
+};
+
+/* This is the list of struct symtab's that gdb considers current. */
+
+struct symtab *symtab_list;
+
+/* This is the list of struct partial_symtab's that gdb may need to access */
+
+struct partial_symtab *partial_symtab_list;
+
+/* This symtab variable specifies the current file for printing source lines */
+
+struct symtab *current_source_symtab;
+
+/* This is the next line to print for listing source lines. */
+
+int current_source_line;
+
+#define BLOCKLIST(symtab) (symtab)->blockvector
+#define BLOCKVECTOR(symtab) (symtab)->blockvector
+
+#define TYPEVECTOR(symtab) (symtab)->typevector
+
+#define LINELIST(symtab) (symtab)->linetable
+#define LINETABLE(symtab) (symtab)->linetable
+
+/* Macros normally used to access components of symbol table structures. */
+
+#define BLOCKLIST_NBLOCKS(blocklist) (blocklist)->nblocks
+#define BLOCKLIST_BLOCK(blocklist,n) (blocklist)->block[n]
+#define BLOCKVECTOR_NBLOCKS(blocklist) (blocklist)->nblocks
+#define BLOCKVECTOR_BLOCK(blocklist,n) (blocklist)->block[n]
+
+#define TYPEVECTOR_NTYPES(typelist) (typelist)->length
+#define TYPEVECTOR_TYPE(typelist,n) (typelist)->type[n]
+
+#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. */
+#define BLOCK_SHOULD_SORT(bl) ((bl)->nsyms >= 40)
+
+#define SYMBOL_NAME(symbol) (symbol)->name
+#define SYMBOL_NAMESPACE(symbol) (symbol)->namespace
+#define SYMBOL_CLASS(symbol) (symbol)->class
+#define SYMBOL_VALUE(symbol) (symbol)->value.value
+#define SYMBOL_VALUE_BYTES(symbol) (symbol)->value.bytes
+#define SYMBOL_BLOCK_VALUE(symbol) (symbol)->value.block
+#define SYMBOL_TYPE(symbol) (symbol)->type
+
+/* Some macros for bitfields. */
+#define B_SET(a,x) (a[x>>5] |= (1 << (x&31)))
+#define B_CLR(a,x) (a[x>>5] &= ~(1 << (x&31)))
+#define B_TST(a,x) (a[x>>5] & (1 << (x&31)))
+
+#define TYPE_NAME(thistype) (thistype)->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_MAIN_VARIANT(thistype) (thistype)->main_variant
+#define TYPE_NEXT_VARIANT(thistype) (thistype)->next_variant
+#define TYPE_LENGTH(thistype) (thistype)->length
+#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
+/* 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) (thistype)->fn_fields
+#define TYPE_NFN_FIELDS(thistype) (thistype)->nfn_fields
+#define TYPE_NFN_FIELDS_TOTAL(thistype) (thistype)->nfn_fields_total
+#define TYPE_BASECLASSES(thistype) (thistype)->baseclasses
+#define TYPE_ARG_TYPES(thistype) (thistype)->arg_types
+#define TYPE_BASECLASS(thistype,index) (thistype)->baseclasses[index]
+#define TYPE_N_BASECLASSES(thistype) (thistype)->n_baseclasses
+#define TYPE_VIA_PUBLIC(thistype) ((thistype)->flags & TYPE_FLAG_VIA_PUBLIC)
+#define TYPE_VIA_VIRTUAL(thistype) ((thistype)->flags & TYPE_FLAG_VIA_VIRTUAL)
+
+#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) (thistype)->private_field_bits
+#define TYPE_FIELD_PROTECTED_BITS(thistype) (thistype)->protected_field_bits
+#define SET_TYPE_FIELD_PRIVATE(thistype, n) B_SET ((thistype)->private_field_bits, (n))
+#define SET_TYPE_FIELD_PROTECTED(thistype, n) B_SET ((thistype)->protected_field_bits, (n))
+#define TYPE_FIELD_PRIVATE(thistype, n) B_TST((thistype)->private_field_bits, (n))
+#define TYPE_FIELD_PROTECTED(thistype, n) B_TST((thistype)->protected_field_bits, (n))
+
+#define TYPE_HAS_DESTRUCTOR(thistype) ((thistype)->flags & TYPE_FLAG_HAS_DESTRUCTOR)
+#define TYPE_HAS_CONSTRUCTOR(thistype) ((thistype)->flags & TYPE_FLAG_HAS_CONSTRUCTOR)
+
+#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) (thistype)->fn_fieldlists
+#define TYPE_FN_FIELDLIST(thistype, n) (thistype)->fn_fieldlists[n]
+#define TYPE_FN_FIELDLIST1(thistype, n) (thistype)->fn_fieldlists[n].fn_fields
+#define TYPE_FN_FIELDLIST_NAME(thistype, n) (thistype)->fn_fieldlists[n].name
+#define TYPE_FN_FIELDLIST_LENGTH(thistype, n) (thistype)->fn_fieldlists[n].length
+
+#define TYPE_FN_FIELD(thistype, n) (thistype)[n]
+#define TYPE_FN_FIELD_NAME(thistype, n) (thistype)[n].name
+#define TYPE_FN_FIELD_TYPE(thistype, n) (thistype)[n].type
+#define TYPE_FN_FIELD_ARGS(thistype, n) (thistype)[n].args
+#define TYPE_FN_FIELD_PHYSNAME(thistype, n) (thistype)[n].physname
+#define TYPE_FN_FIELD_VIRTUAL_P(thistype, n) ((thistype)[n].voffset < 0)
+#define TYPE_FN_FIELD_STATIC_P(thistype, n) ((thistype)[n].voffset > 0)
+#define TYPE_FN_FIELD_VOFFSET(thistype, n) ((thistype)[n].voffset-1)
+
+#define TYPE_FN_PRIVATE_BITS(thistype) (thistype).private_fn_field_bits
+#define TYPE_FN_PROTECTED_BITS(thistype) (thistype).protected_fn_field_bits
+#define SET_TYPE_FN_PRIVATE(thistype, n) B_SET ((thistype).private_fn_field_bits, n)
+#define SET_TYPE_FN_PROTECTED(thistype, n) B_SET ((thistype).protected_fn_field_bits, n)
+#define TYPE_FN_PRIVATE(thistype, n) B_TST ((thistype).private_fn_field_bits, n)
+#define TYPE_FN_PROTECTED(thistype, n) B_TST ((thistype).protected_fn_field_bits, n)
+
+/* Functions that work on the objects described above */
+
+extern struct symtab *lookup_symtab ();
+extern struct symbol *lookup_symbol ();
+extern struct type *lookup_typename ();
+extern struct type *lookup_unsigned_typename ();
+extern struct type *lookup_struct ();
+extern struct type *lookup_union ();
+extern struct type *lookup_enum ();
+extern struct type *lookup_struct_elt_type ();
+extern struct type *lookup_pointer_type ();
+extern struct type *lookup_function_type ();
+extern struct type *lookup_basetype_type ();
+extern struct type *create_array_type ();
+extern struct symbol *block_function ();
+extern struct symbol *find_pc_function ();
+extern int find_pc_partial_function ();
+extern struct partial_symtab *find_pc_psymtab ();
+extern struct symtab *find_pc_symtab ();
+extern struct partial_symbol *find_pc_psymbol ();
+extern int find_pc_misc_function ();
+
+/* C++ stuff. */
+extern struct type *lookup_reference_type ();
+extern struct type *lookup_member_type ();
+extern struct type *lookup_class ();
+/* end of C++ stuff. */
+
+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_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;
+
+#ifdef LONG_LONG
+extern struct type *builtin_type_long_long;
+extern struct type *builtin_type_unsigned_long_long;
+
+#ifndef BUILTIN_TYPE_LONGEST
+#define BUILTIN_TYPE_LONGEST builtin_type_long_long
+#endif
+
+#ifndef BUILTIN_TYPE_UNSIGNED_LONGEST
+#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long_long
+#endif
+
+#else /* LONG_LONG */
+
+#ifndef BUILTIN_TYPE_LONGEST
+#define BUILTIN_TYPE_LONGEST builtin_type_long
+#endif
+
+#ifndef BUILTIN_TYPE_UNSIGNED_LONGEST
+#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long
+#endif
+
+#endif
+
+struct symtab_and_line
+{
+ struct symtab *symtab;
+ 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. */
+
+struct symtab_and_line find_pc_line ();
+
+/* Given a string, return the line specified by it.
+ For commands like "list" and "breakpoint". */
+
+struct symtabs_and_lines decode_line_spec ();
+struct symtabs_and_lines decode_line_spec_1 ();
+struct symtabs_and_lines decode_line_1 ();
diff --git a/gnu/usr.bin/gdb/utils.c b/gnu/usr.bin/gdb/utils.c
new file mode 100644
index 0000000..b03f2be
--- /dev/null
+++ b/gnu/usr.bin/gdb/utils.c
@@ -0,0 +1,1096 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ *
+ * $Header: /home/cvs/386BSD/src/usr.bin/gdb/utils.c,v 1.1.1.1 1993/06/12 14:52:20 rgrimes Exp $;
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)utils.c 6.4 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* General utility routines for GDB, the GNU debugger.
+ Copyright (C) 1986, 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. */
+
+#include "param.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include "defs.h"
+#ifdef HAVE_TERMIO
+#include <termio.h>
+#endif
+
+/* 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
+
+extern FILE *instream;
+
+void error ();
+void fatal ();
+
+/* Chain of cleanup actions established with make_cleanup,
+ to be executed if an error happens. */
+
+static struct cleanup *cleanup_chain;
+
+/* 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. */
+
+int immediate_quit;
+
+/* 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) ();
+ int 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)
+ {
+ (*ptr->function) (ptr->arg);
+ cleanup_chain = ptr->next;
+ 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);
+ }
+}
+
+/* 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);
+}
+
+/* Generally useful subroutines used throughout the program. */
+
+/* Like malloc but get error if no storage available. */
+
+char *
+xmalloc (size)
+ long size;
+{
+ register char *val = (char *) malloc (size);
+ if (!val)
+ fatal ("virtual memory exhausted.", 0);
+ return val;
+}
+
+/* Like realloc but get error if no storage available. */
+
+char *
+xrealloc (ptr, size)
+ char *ptr;
+ long size;
+{
+ register char *val = (char *) realloc (ptr, size);
+ if (!val)
+ fatal ("virtual memory exhausted.", 0);
+ return val;
+}
+
+/* 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;
+{
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ extern int errno;
+ char *err;
+ char *combined;
+
+ if (errno < sys_nerr)
+ err = sys_errlist[errno];
+ else
+ err = "unknown error";
+
+ combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+ strcpy (combined, string);
+ strcat (combined, ": ");
+ strcat (combined, err);
+
+ 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;
+{
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ char *err;
+ char *combined;
+
+ if (errcode < sys_nerr)
+ err = sys_errlist[errcode];
+ else
+ err = "unknown error";
+
+ combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+ strcpy (combined, string);
+ strcat (combined, ": ");
+ strcat (combined, err);
+
+ printf ("%s.\n", combined);
+}
+
+void
+quit ()
+{
+#ifdef HAVE_TERMIO
+ ioctl (fileno (stdout), TCFLSH, 1);
+#else /* not HAVE_TERMIO */
+ ioctl (fileno (stdout), TIOCFLUSH, 0);
+#endif /* not HAVE_TERMIO */
+#ifdef TIOCGPGRP
+ error ("Quit");
+#else
+ error ("Quit (expect signal %d when inferior is resumed)", SIGINT);
+#endif /* TIOCGPGRP */
+}
+
+/* Control C comes here */
+
+void
+request_quit ()
+{
+ extern int remote_debugging;
+
+ quit_flag = 1;
+
+#ifdef USG
+ /* Restore the signal handler. */
+ signal (SIGINT, request_quit);
+#endif
+
+ if (immediate_quit)
+ quit();
+}
+
+/* Print an error message and return to command level.
+ STRING is the error message, used as a fprintf string,
+ and ARG is passed as an argument to it. */
+
+void
+error (string, arg1, arg2, arg3)
+ char *string;
+ int arg1, arg2, arg3;
+{
+ terminal_ours (); /* Should be ok even if no inf. */
+ fflush (stdout);
+ fprintf (stderr, string, arg1, arg2, arg3);
+ fprintf (stderr, "\n");
+ return_to_top_level ();
+}
+
+/* Print an error message and exit reporting failure.
+ This is for a error that we cannot continue from.
+ STRING and ARG are passed to fprintf. */
+
+void
+fatal (string, arg)
+ char *string;
+ int arg;
+{
+ fprintf (stderr, "gdb: ");
+ fprintf (stderr, string, arg);
+ fprintf (stderr, "\n");
+ exit (1);
+}
+
+/* Print an error message and exit, dumping core.
+ STRING is a printf-style control string, and ARG is a corresponding
+ argument. */
+void
+fatal_dump_core (string, arg)
+ char *string;
+ int arg;
+{
+ /* "internal error" is always correct, since GDB should never dump
+ core, no matter what the input. */
+ fprintf (stderr, "gdb internal error: ");
+ fprintf (stderr, string, arg);
+ fprintf (stderr, "\n");
+ signal (SIGQUIT, SIG_DFL);
+ kill (getpid (), SIGQUIT);
+ /* We should never get here, but just in case... */
+ exit (1);
+}
+
+/* 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)
+ char *ptr;
+ int size;
+{
+ register char *p = (char *) xmalloc (size + 1);
+ bcopy (ptr, p, size);
+ p[size] = 0;
+ return p;
+}
+
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
+ register char *val = (char *) xmalloc (len);
+ strcpy (val, s1);
+ strcat (val, s2);
+ strcat (val, s3);
+ return val;
+}
+
+void
+print_spaces (n, file)
+ register int n;
+ register FILE *file;
+{
+ while (n-- > 0)
+ fputc (' ', file);
+}
+
+/* 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. */
+
+int
+query (ctlstr, arg1, arg2)
+ char *ctlstr;
+{
+ register int answer;
+
+ /* Automatically answer "yes" if input is not from a terminal. */
+ if (!input_from_terminal_p ())
+ return 1;
+
+ while (1)
+ {
+ printf (ctlstr, arg1, arg2);
+ printf ("(y or n) ");
+ fflush (stdout);
+ answer = fgetc (stdin);
+ clearerr (stdin); /* in case of C-d */
+ if (answer != '\n')
+ while (fgetc (stdin) != '\n') clearerr (stdin);
+ if (answer >= 'a')
+ answer -= 040;
+ if (answer == 'Y')
+ return 1;
+ if (answer == 'N')
+ return 0;
+ printf ("Please answer y or n.\n");
+ }
+}
+
+/* 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.
+
+ 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 '\a';
+ case 'b':
+ return '\b';
+ case 'e':
+ 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 CH on STREAM as part of the contents
+ of a literal string whose delimiter is QUOTER. */
+
+void
+printchar (ch, stream, quoter)
+ unsigned char ch;
+ FILE *stream;
+ int quoter;
+{
+ register int c = ch;
+ if (c < 040 || c >= 0177)
+ 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);
+ }
+}
+
+static int lines_per_page, lines_printed, chars_per_line, chars_printed;
+
+/* Set values of page and line size. */
+static void
+set_screensize_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ char *p = arg;
+ char *p1;
+ int tolinesize = lines_per_page;
+ int tocharsize = chars_per_line;
+
+ if (p == 0)
+ error_no_arg ("set screensize");
+
+ while (*p >= '0' && *p <= '9')
+ p++;
+
+ if (*p && *p != ' ' && *p != '\t')
+ error ("Non-integral argument given to \"set screensize\".");
+
+ tolinesize = atoi (arg);
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ if (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9')
+ p1++;
+
+ if (*p1)
+ error ("Non-integral second argument given to \"set screensize\".");
+
+ tocharsize = atoi (p);
+ }
+
+ lines_per_page = tolinesize;
+ chars_per_line = tocharsize;
+}
+
+static void
+instream_cleanup(stream)
+ FILE *stream;
+{
+ instream = stream;
+}
+
+static void
+prompt_for_continue ()
+{
+ if (ISATTY(stdin) && ISATTY(stdout))
+ {
+ struct cleanup *old_chain = make_cleanup(instream_cleanup, instream);
+ char *cp, *gdb_readline();
+
+ instream = stdin;
+ immediate_quit++;
+ if (cp = gdb_readline ("---Type <return> to continue---"))
+ free(cp);
+ chars_printed = lines_printed = 0;
+ immediate_quit--;
+ do_cleanups(old_chain);
+ }
+}
+
+/* Reinitialize filter; ie. tell it to reset to original values. */
+
+void
+reinitialize_more_filter ()
+{
+ lines_printed = 0;
+ chars_printed = 0;
+}
+
+static void
+screensize_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (arg)
+ error ("\"info screensize\" does not take any arguments.");
+
+ if (!lines_per_page)
+ printf ("Output more filtering is disabled.\n");
+ else
+ {
+ printf ("Output more filtering is enabled with\n");
+ printf ("%d lines per page and %d characters per line.\n",
+ lines_per_page, chars_per_line);
+ }
+}
+
+/* Like fputs but pause after every screenful.
+ Unlike fputs, fputs_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
+ (since prompt_for_continue may do so) so this routine should not be
+ called when cleanups are not in place. */
+
+void
+fputs_filtered (linebuffer, stream)
+ char *linebuffer;
+ FILE *stream;
+{
+ char *lineptr;
+
+ if (linebuffer == 0)
+ return;
+
+ /* Don't do any filtering if it is disabled. */
+ if (stream != stdout || !ISATTY(stdout) || lines_per_page == 0)
+ {
+ fputs (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 (lines_printed >= lines_per_page - 1)
+ prompt_for_continue ();
+
+ while (*lineptr && *lineptr != '\n')
+ {
+ /* Print a single line. */
+ if (*lineptr == '\t')
+ {
+ putc ('\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
+ {
+ putc (*lineptr, stream);
+ chars_printed++;
+ lineptr++;
+ }
+
+ if (chars_printed >= chars_per_line)
+ {
+ chars_printed = 0;
+ lines_printed++;
+ /* Possible new page. */
+ if (lines_printed >= lines_per_page - 1)
+ prompt_for_continue ();
+ }
+ }
+
+ if (*lineptr == '\n')
+ {
+ lines_printed++;
+ putc ('\n', stream);
+ lineptr++;
+ chars_printed = 0;
+ }
+ }
+}
+
+/* fputs_demangled is a variant of fputs_filtered that
+ demangles g++ names.*/
+
+void
+fputs_demangled (linebuffer, stream, arg_mode)
+ char *linebuffer;
+ FILE *stream;
+{
+#ifdef __STDC__
+ extern char *cplus_demangle (const char *, int);
+#else
+ extern char *cplus_demangle ();
+#endif
+#define SYMBOL_MAX 1024
+
+#define SYMBOL_CHAR(c) (isascii(c) && (isalnum(c) || (c) == '_' || (c) == '$'))
+
+ char buf[SYMBOL_MAX+1];
+ char *p;
+
+ if (linebuffer == NULL)
+ return;
+
+ p = linebuffer;
+
+ while ( *p != (char) 0 ) {
+ int i = 0;
+
+ /* collect non-interesting characters into buf */
+ while ( *p != (char) 0 && !SYMBOL_CHAR(*p) ) {
+ buf[i++] = *p;
+ p++;
+ }
+ if (i > 0) {
+ /* output the non-interesting characters without demangling */
+ buf[i] = (char) 0;
+ fputs_filtered(buf, stream);
+ i = 0; /* reset buf */
+ }
+
+ /* and now the interesting characters */
+ while (i < SYMBOL_MAX && *p != (char) 0 && SYMBOL_CHAR(*p) ) {
+ buf[i++] = *p;
+ p++;
+ }
+ buf[i] = (char) 0;
+ if (i > 0) {
+ char * result;
+
+ if ( (result = cplus_demangle(buf, arg_mode)) != NULL ) {
+ fputs_filtered(result, stream);
+ free(result);
+ }
+ else {
+ fputs_filtered(buf, stream);
+ }
+ }
+ }
+}
+
+/* Print ARG1, ARG2, and ARG3 on stdout using format FORMAT. If this
+ information is going to put the amount written since the last call
+ to INIIALIZE_MORE_FILTER or the last page break over the page size,
+ print out a pause message and do a gdb_readline to get the users
+ permision to continue.
+
+ Unlike fprintf, this function does not return a value.
+
+ Note that this routine has a restriction that the length of the
+ final output line must be less than 255 characters *or* it must be
+ less than twice the size of the format string. This is a very
+ arbitrary restriction, but it is an internal restriction, so I'll
+ put it in. This means that the %s format specifier is almost
+ useless; unless the caller can GUARANTEE that the string is short
+ enough, fputs_filtered should be used instead.
+
+ 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. */
+
+void
+fprintf_filtered (stream, format, arg1, arg2, arg3, arg4, arg5, arg6)
+ FILE *stream;
+ char *format;
+ int arg1, arg2, arg3, arg4, arg5, arg6;
+{
+ static char *linebuffer = (char *) 0;
+ static int line_size;
+ int format_length = strlen (format);
+ int numchars;
+
+ /* Allocated linebuffer for the first time. */
+ if (!linebuffer)
+ {
+ linebuffer = (char *) xmalloc (255);
+ line_size = 255;
+ }
+
+ /* Reallocate buffer to a larger size if this is necessary. */
+ if (format_length * 2 > line_size)
+ {
+ line_size = format_length * 2;
+
+ /* You don't have to copy. */
+ free (linebuffer);
+ linebuffer = (char *) xmalloc (line_size);
+ }
+
+ /* This won't blow up if the restrictions described above are
+ followed. */
+ (void) sprintf (linebuffer, format, arg1, arg2, arg3, arg4, arg5, arg6);
+
+ fputs_filtered (linebuffer, stream);
+}
+
+void
+printf_filtered (format, arg1, arg2, arg3, arg4, arg5, arg6)
+ char *format;
+ int arg1, arg2, arg3, arg4, arg5, arg6;
+{
+ fprintf_filtered (stdout, format, arg1, arg2, arg3, arg4, arg5, arg6);
+}
+
+/* Print N spaces. */
+void
+print_spaces_filtered (n, stream)
+ int n;
+ FILE *stream;
+{
+ register char *s = (char *) alloca (n + 1);
+ register char *t = s;
+
+ while (n--)
+ *t++ = ' ';
+ *t = '\0';
+
+ fputs_filtered (s, stream);
+}
+
+
+#ifdef USG
+bcopy (from, to, count)
+char *from, *to;
+{
+ memcpy (to, from, count);
+}
+
+bcmp (from, to, count)
+{
+ return (memcmp (to, from, count));
+}
+
+bzero (to, count)
+char *to;
+{
+ while (count--)
+ *to++ = 0;
+}
+
+getwd (buf)
+char *buf;
+{
+ getcwd (buf, MAXPATHLEN);
+}
+
+char *
+index (s, c)
+ char *s;
+{
+ char *strchr ();
+ return strchr (s, c);
+}
+
+char *
+rindex (s, c)
+ char *s;
+{
+ char *strrchr ();
+ return strrchr (s, c);
+}
+
+#ifndef USG
+char *sys_siglist[32] = {
+ "SIG0",
+ "SIGHUP",
+ "SIGINT",
+ "SIGQUIT",
+ "SIGILL",
+ "SIGTRAP",
+ "SIGIOT",
+ "SIGEMT",
+ "SIGFPE",
+ "SIGKILL",
+ "SIGBUS",
+ "SIGSEGV",
+ "SIGSYS",
+ "SIGPIPE",
+ "SIGALRM",
+ "SIGTERM",
+ "SIGUSR1",
+ "SIGUSR2",
+ "SIGCLD",
+ "SIGPWR",
+ "SIGWIND",
+ "SIGPHONE",
+ "SIGPOLL",
+};
+#endif
+
+/* Queue routines */
+
+struct queue {
+ struct queue *forw;
+ struct queue *back;
+};
+
+insque (item, after)
+struct queue *item;
+struct queue *after;
+{
+ item->forw = after->forw;
+ after->forw->back = item;
+
+ item->back = after;
+ after->forw = item;
+}
+
+remque (item)
+struct queue *item;
+{
+ item->forw->back = item->back;
+ item->back->forw = item->forw;
+}
+#endif /* USG */
+
+#ifdef USG
+/* There is too much variation in Sys V signal numbers and names, so
+ we must initialize them at runtime. */
+static char undoc[] = "(undocumented)";
+
+char *sys_siglist[NSIG];
+#endif /* USG */
+
+extern struct cmd_list_element *setlist;
+
+void
+_initialize_utils ()
+{
+ int i;
+ add_cmd ("screensize", class_support, set_screensize_command,
+ "Change gdb's notion of the size of the output screen.\n\
+The first argument is the number of lines on a page.\n\
+The second argument (optional) is the number of characters on a line.",
+ &setlist);
+ add_info ("screensize", screensize_info,
+ "Show gdb's current notion of the size of the output screen.");
+
+ /* These defaults will be used if we are unable to get the correct
+ values from termcap. */
+ lines_per_page = 24;
+ chars_per_line = 80;
+ /* Initialize the screen height and width from termcap. */
+ {
+ int 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 = 0;
+
+ val = tgetnum ("co");
+ if (val >= 0)
+ chars_per_line = val;
+ }
+ }
+ }
+
+#ifdef USG
+ /* Initialize signal names. */
+ for (i = 0; i < NSIG; i++)
+ sys_siglist[i] = undoc;
+
+#ifdef SIGHUP
+ sys_siglist[SIGHUP ] = "SIGHUP";
+#endif
+#ifdef SIGINT
+ sys_siglist[SIGINT ] = "SIGINT";
+#endif
+#ifdef SIGQUIT
+ sys_siglist[SIGQUIT ] = "SIGQUIT";
+#endif
+#ifdef SIGILL
+ sys_siglist[SIGILL ] = "SIGILL";
+#endif
+#ifdef SIGTRAP
+ sys_siglist[SIGTRAP ] = "SIGTRAP";
+#endif
+#ifdef SIGIOT
+ sys_siglist[SIGIOT ] = "SIGIOT";
+#endif
+#ifdef SIGEMT
+ sys_siglist[SIGEMT ] = "SIGEMT";
+#endif
+#ifdef SIGFPE
+ sys_siglist[SIGFPE ] = "SIGFPE";
+#endif
+#ifdef SIGKILL
+ sys_siglist[SIGKILL ] = "SIGKILL";
+#endif
+#ifdef SIGBUS
+ sys_siglist[SIGBUS ] = "SIGBUS";
+#endif
+#ifdef SIGSEGV
+ sys_siglist[SIGSEGV ] = "SIGSEGV";
+#endif
+#ifdef SIGSYS
+ sys_siglist[SIGSYS ] = "SIGSYS";
+#endif
+#ifdef SIGPIPE
+ sys_siglist[SIGPIPE ] = "SIGPIPE";
+#endif
+#ifdef SIGALRM
+ sys_siglist[SIGALRM ] = "SIGALRM";
+#endif
+#ifdef SIGTERM
+ sys_siglist[SIGTERM ] = "SIGTERM";
+#endif
+#ifdef SIGUSR1
+ sys_siglist[SIGUSR1 ] = "SIGUSR1";
+#endif
+#ifdef SIGUSR2
+ sys_siglist[SIGUSR2 ] = "SIGUSR2";
+#endif
+#ifdef SIGCLD
+ sys_siglist[SIGCLD ] = "SIGCLD";
+#endif
+#ifdef SIGCHLD
+ sys_siglist[SIGCHLD ] = "SIGCHLD";
+#endif
+#ifdef SIGPWR
+ sys_siglist[SIGPWR ] = "SIGPWR";
+#endif
+#ifdef SIGTSTP
+ sys_siglist[SIGTSTP ] = "SIGTSTP";
+#endif
+#ifdef SIGTTIN
+ sys_siglist[SIGTTIN ] = "SIGTTIN";
+#endif
+#ifdef SIGTTOU
+ sys_siglist[SIGTTOU ] = "SIGTTOU";
+#endif
+#ifdef SIGSTOP
+ sys_siglist[SIGSTOP ] = "SIGSTOP";
+#endif
+#ifdef SIGXCPU
+ sys_siglist[SIGXCPU ] = "SIGXCPU";
+#endif
+#ifdef SIGXFSZ
+ sys_siglist[SIGXFSZ ] = "SIGXFSZ";
+#endif
+#ifdef SIGVTALRM
+ sys_siglist[SIGVTALRM ] = "SIGVTALRM";
+#endif
+#ifdef SIGPROF
+ sys_siglist[SIGPROF ] = "SIGPROF";
+#endif
+#ifdef SIGWINCH
+ sys_siglist[SIGWINCH ] = "SIGWINCH";
+#endif
+#ifdef SIGCONT
+ sys_siglist[SIGCONT ] = "SIGCONT";
+#endif
+#ifdef SIGURG
+ sys_siglist[SIGURG ] = "SIGURG";
+#endif
+#ifdef SIGIO
+ sys_siglist[SIGIO ] = "SIGIO";
+#endif
+#ifdef SIGWIND
+ sys_siglist[SIGWIND ] = "SIGWIND";
+#endif
+#ifdef SIGPHONE
+ sys_siglist[SIGPHONE ] = "SIGPHONE";
+#endif
+#ifdef SIGPOLL
+ sys_siglist[SIGPOLL ] = "SIGPOLL";
+#endif
+#endif /* USG */
+}
diff --git a/gnu/usr.bin/gdb/valarith.c b/gnu/usr.bin/gdb/valarith.c
new file mode 100644
index 0000000..8e76899
--- /dev/null
+++ b/gnu/usr.bin/gdb/valarith.c
@@ -0,0 +1,690 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)valarith.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Perform arithmetic and other operations on values, for GDB.
+ Copyright (C) 1986, 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. */
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "value.h"
+#include "expression.h"
+
+
+value value_x_binop ();
+value value_subscripted_rvalue ();
+
+value
+value_add (arg1, arg2)
+ value arg1, arg2;
+{
+ register value val, 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 *) */
+ val = value_from_long (builtin_type_long,
+ value_as_long (valptr)
+ + (len * value_as_long (valint)));
+ VALUE_TYPE (val) = VALUE_TYPE (valptr);
+ return val;
+ }
+
+ return value_binop (arg1, arg2, BINOP_ADD);
+}
+
+value
+value_sub (arg1, arg2)
+ value arg1, arg2;
+{
+ register value val;
+
+ COERCE_ARRAY (arg1);
+ COERCE_ARRAY (arg2);
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR
+ &&
+ TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT)
+ {
+ val = value_from_long (builtin_type_long,
+ value_as_long (arg1)
+ - TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) * value_as_long (arg2));
+ VALUE_TYPE (val) = VALUE_TYPE (arg1);
+ return val;
+ }
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR
+ &&
+ VALUE_TYPE (arg1) == VALUE_TYPE (arg2))
+ {
+ val = value_from_long (builtin_type_long,
+ (value_as_long (arg1) - value_as_long (arg2))
+ / TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))));
+ return val;
+ }
+
+ return value_binop (arg1, arg2, BINOP_SUB);
+}
+
+/* Return the value of ARRAY[IDX]. */
+
+value
+value_subscript (array, idx)
+ value array, idx;
+{
+ if (TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_ARRAY
+ && VALUE_LVAL (array) != lval_memory)
+ return value_subscripted_rvalue (array, idx);
+ else
+ return value_ind (value_add (array, idx));
+}
+
+/* Return the value of EXPR[IDX], expr an aggregate rvalue
+ (eg, a vector register) */
+
+value
+value_subscripted_rvalue (array, idx)
+ value array, idx;
+{
+ struct type *elt_type = TYPE_TARGET_TYPE (VALUE_TYPE (array));
+ int elt_size = TYPE_LENGTH (elt_type);
+ int elt_offs = elt_size * value_as_long (idx);
+ value v;
+
+ if (elt_offs >= TYPE_LENGTH (VALUE_TYPE (array)))
+ error ("no such vector element");
+
+ if (TYPE_CODE (elt_type) == TYPE_CODE_FLT)
+ {
+ if (elt_size == sizeof (float))
+ v = value_from_double (elt_type, (double) *(float *)
+ (VALUE_CONTENTS (array) + elt_offs));
+ else
+ v = value_from_double (elt_type, *(double *)
+ (VALUE_CONTENTS (array) + elt_offs));
+ }
+ else
+ {
+ int offs;
+ union {int i; char c;} test;
+ test.i = 1;
+ if (test.c == 1)
+ offs = 0;
+ else
+ offs = sizeof (LONGEST) - elt_size;
+ v = value_from_long (elt_type, *(LONGEST *)
+ (VALUE_CONTENTS (array) + elt_offs - offs));
+ }
+
+ 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 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 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++). */
+
+value
+value_x_binop (arg1, arg2, op, otherop)
+ value arg1, arg2;
+ int op, otherop;
+{
+ value * argvec;
+ char *ptr;
+ char tstr[13];
+ int static_memfuncp;
+
+ 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 ("friend functions not implemented yet");
+
+ argvec = (value *) alloca (sizeof (value) * 4);
+ argvec[1] = value_addr (arg1);
+ argvec[2] = arg2;
+ argvec[3] = 0;
+
+ /* make the right function name up */
+ strcpy(tstr, "operator __");
+ ptr = tstr+9;
+ 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_LOGAND: strcpy(ptr,"&"); break;
+ case BINOP_LOGIOR: strcpy(ptr,"|"); break;
+ case BINOP_LOGXOR: strcpy(ptr,"^"); break;
+ case BINOP_AND: strcpy(ptr,"&&"); break;
+ case BINOP_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_LOGAND: strcpy(ptr,"&="); break;
+ case BINOP_LOGIOR: strcpy(ptr,"|="); break;
+ case BINOP_LOGXOR: strcpy(ptr,"^="); break;
+ 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;
+ 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 (argvec[0], 2 - static_memfuncp, argvec + 1);
+ }
+ error ("member function %s not found", tstr);
+}
+
+/* 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
+value_x_unop (arg1, op)
+ value arg1;
+ int op;
+{
+ value * argvec;
+ char *ptr;
+ char 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 ("friend functions not implemented yet");
+
+ argvec = (value *) alloca (sizeof (value) * 3);
+ argvec[1] = value_addr (arg1);
+ argvec[2] = 0;
+
+ /* make the right function name up */
+ strcpy(tstr,"operator __");
+ ptr = tstr+9;
+ 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_ZEROP: strcpy(ptr,"!"); break;
+ case UNOP_LOGNOT: 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 (argvec[0], 1 - static_memfuncp, argvec + 1);
+ }
+ error ("member function %s not found", tstr);
+}
+
+/* Perform a binary operation on two integers or two floats.
+ Does not support addition and subtraction on pointers;
+ use value_add or value_sub if you want to handle those possibilities. */
+
+value
+value_binop (arg1, arg2, op)
+ value arg1, arg2;
+ int op;
+{
+ register value val;
+
+ COERCE_ENUM (arg1);
+ COERCE_ENUM (arg2);
+
+ if ((TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_FLT
+ &&
+ TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT)
+ ||
+ (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_FLT
+ &&
+ TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT))
+ error ("Argument to arithmetic operation not a number.");
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_FLT
+ ||
+ TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_FLT)
+ {
+ 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);
+ *(double *) VALUE_CONTENTS (val) = v;
+ }
+ else
+ /* Integral operations here. */
+ {
+ /* 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_LSH:
+ v = v1 << v2;
+ break;
+
+ case BINOP_RSH:
+ v = v1 >> v2;
+ break;
+
+ case BINOP_LOGAND:
+ v = v1 & v2;
+ break;
+
+ case BINOP_LOGIOR:
+ v = v1 | v2;
+ break;
+
+ case BINOP_LOGXOR:
+ v = v1 ^ v2;
+ break;
+
+ case BINOP_AND:
+ v = v1 && v2;
+ break;
+
+ case BINOP_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.");
+ }
+
+ val = allocate_value (BUILTIN_TYPE_UNSIGNED_LONGEST);
+ *(unsigned LONGEST *) VALUE_CONTENTS (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_LSH:
+ v = v1 << v2;
+ break;
+
+ case BINOP_RSH:
+ v = v1 >> v2;
+ break;
+
+ case BINOP_LOGAND:
+ v = v1 & v2;
+ break;
+
+ case BINOP_LOGIOR:
+ v = v1 | v2;
+ break;
+
+ case BINOP_LOGXOR:
+ v = v1 ^ v2;
+ break;
+
+ case BINOP_AND:
+ v = v1 && v2;
+ break;
+
+ case BINOP_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.");
+ }
+
+ val = allocate_value (BUILTIN_TYPE_LONGEST);
+ *(LONGEST *) VALUE_CONTENTS (val) = v;
+ }
+ }
+
+ return val;
+}
+
+/* Simulate the C operator ! -- return 1 if ARG1 contains zeros. */
+
+int
+value_zerop (arg1)
+ value arg1;
+{
+ register int len;
+ register char *p;
+
+ COERCE_ARRAY (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 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);
+ else if ((code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_INT)
+ || (code2 == TYPE_CODE_PTR && code1 == TYPE_CODE_INT))
+ return (char *) value_as_long (arg1) == (char *) value_as_long (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.");
+}
+
+/* Simulate the C operator < by returning 1
+ iff ARG1's contents are less than ARG2's. */
+
+int
+value_less (arg1, arg2)
+ register value 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)
+ 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 || code1 == TYPE_CODE_INT)
+ && (code2 == TYPE_CODE_PTR || code2 == TYPE_CODE_INT))
+ return (char *) value_as_long (arg1) < (char *) value_as_long (arg2);
+ else
+ error ("Invalid type combination in ordering comparison.");
+}
+
+/* The unary operators - and ~. Both free the argument ARG1. */
+
+value
+value_neg (arg1)
+ register value 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_long (type, - value_as_long (arg1));
+ else
+ error ("Argument to negate operation not a number.");
+}
+
+value
+value_lognot (arg1)
+ register value arg1;
+{
+ COERCE_ENUM (arg1);
+
+ if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT)
+ error ("Argument to complement operation not an integer.");
+
+ return value_from_long (VALUE_TYPE (arg1), ~ value_as_long (arg1));
+}
+
diff --git a/gnu/usr.bin/gdb/valops.c b/gnu/usr.bin/gdb/valops.c
new file mode 100644
index 0000000..ab5652c
--- /dev/null
+++ b/gnu/usr.bin/gdb/valops.c
@@ -0,0 +1,1418 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)valops.c 6.4 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Perform non-arithmetic operations on values, for GDB.
+ 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. */
+
+#include "stdio.h"
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "value.h"
+#include "frame.h"
+#include "inferior.h"
+
+/* 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. */
+
+value
+value_cast (type, arg2)
+ struct type *type;
+ register value 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_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_long (type, value_as_long (arg2));
+ else if (TYPE_LENGTH (type) == TYPE_LENGTH (VALUE_TYPE (arg2)))
+ {
+ VALUE_TYPE (arg2) = type;
+ return arg2;
+ }
+ else if (VALUE_LVAL (arg2) == lval_memory)
+ {
+ return value_at (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2));
+ }
+ else
+ error ("Invalid cast.");
+}
+
+/* Create a value of type TYPE that is zero, and return it. */
+
+value
+value_zero (type, lv)
+ struct type *type;
+ enum lval_type lv;
+{
+ register value val = allocate_value (type);
+
+ bzero (VALUE_CONTENTS (val), TYPE_LENGTH (type));
+ VALUE_LVAL (val) = lv;
+
+ return val;
+}
+
+/* Return the value with a specified type located at specified address. */
+
+value
+value_at (type, addr)
+ struct type *type;
+ CORE_ADDR addr;
+{
+ register value val = allocate_value (type);
+ int temp;
+
+ temp = read_memory (addr, VALUE_CONTENTS (val), TYPE_LENGTH (type));
+ if (temp)
+ {
+ if (have_inferior_p () && !remote_debugging)
+ print_sys_errmsg ("ptrace", temp);
+ /* Actually, address between addr and addr + len was out of bounds. */
+ error ("Cannot read memory: address 0x%x out of bounds.", addr);
+ }
+
+ VALUE_LVAL (val) = lval_memory;
+ VALUE_ADDRESS (val) = addr;
+
+ return val;
+}
+
+/* Store the contents of FROMVAL into the location of TOVAL.
+ Return a new value with the location of TOVAL and contents of FROMVAL. */
+
+value
+value_assign (toval, fromval)
+ register value toval, fromval;
+{
+ register struct type *type = VALUE_TYPE (toval);
+ register value val;
+ char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+ int use_buffer = 0;
+
+ extern CORE_ADDR find_saved_register ();
+
+ COERCE_ARRAY (fromval);
+
+ 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. */
+
+ if (VALUE_REGNO (toval) >= 0
+ && REGISTER_CONVERTIBLE (VALUE_REGNO (toval)))
+ {
+ int regno = VALUE_REGNO (toval);
+ if (VALUE_TYPE (fromval) != REGISTER_VIRTUAL_TYPE (regno))
+ fromval = value_cast (REGISTER_VIRTUAL_TYPE (regno), fromval);
+ bcopy (VALUE_CONTENTS (fromval), virtual_buffer,
+ REGISTER_VIRTUAL_SIZE (regno));
+ REGISTER_CONVERT_TO_RAW (regno, virtual_buffer, raw_buffer);
+ use_buffer = REGISTER_RAW_SIZE (regno);
+ }
+
+ 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))
+ {
+ int val;
+ read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ &val, sizeof val);
+ modify_field (&val, (int) value_as_long (fromval),
+ VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+ write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ &val, sizeof val);
+ }
+ 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))
+ {
+ int val;
+
+ read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ &val, sizeof val);
+ modify_field (&val, (int) value_as_long (fromval),
+ VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+ write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ &val, sizeof val);
+ }
+ else if (use_buffer)
+ write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ raw_buffer, use_buffer);
+ else
+ write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+ VALUE_CONTENTS (fromval), TYPE_LENGTH (type));
+ 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;
+ char *buffer = (char *) alloca (amount_to_copy);
+ int regno;
+ FRAME frame;
+ CORE_ADDR addr;
+
+ /* 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++)
+ {
+ addr = find_saved_register (frame, regno);
+ if (addr == 0)
+ read_register_bytes (REGISTER_BYTE (regno),
+ buffer + amount_copied,
+ reg_size);
+ else
+ read_memory (addr, buffer + amount_copied, reg_size);
+ }
+
+ /* Modify what needs to be modified. */
+ if (VALUE_BITSIZE (toval))
+ modify_field (buffer + byte_offset,
+ (int) value_as_long (fromval),
+ VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+ else if (use_buffer)
+ bcopy (raw_buffer, buffer + byte_offset, use_buffer);
+ else
+ bcopy (VALUE_CONTENTS (fromval), buffer + byte_offset,
+ 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++)
+ {
+ addr = find_saved_register (frame, regno);
+ if (addr == 0)
+ write_register_bytes (REGISTER_BYTE (regno),
+ buffer + amount_copied,
+ reg_size);
+ else
+ write_memory (addr, buffer + amount_copied, reg_size);
+ }
+ }
+ break;
+
+
+ default:
+ error ("Left side of = operation 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);
+ bcopy (toval, val, VALUE_CONTENTS (val) - (char *) val);
+ bcopy (VALUE_CONTENTS (fromval), VALUE_CONTENTS (val), TYPE_LENGTH (type));
+ VALUE_TYPE (val) = type;
+
+ return val;
+}
+
+/* Extend a value VAL to COUNT repetitions of its type. */
+
+value
+value_repeat (arg1, count)
+ value arg1;
+ int count;
+{
+ register value 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 (val),
+ TYPE_LENGTH (VALUE_TYPE (val)) * count);
+ VALUE_LVAL (val) = lval_memory;
+ VALUE_ADDRESS (val) = VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1);
+
+ return val;
+}
+
+value
+value_of_variable (var)
+ struct symbol *var;
+{
+ return read_var_value (var, (FRAME) 0);
+}
+
+/* Given a value which is an array, return a value which is
+ a pointer to its first element. */
+
+value
+value_coerce_array (arg1)
+ value arg1;
+{
+ register struct type *type;
+ register value val;
+
+ 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 = 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);
+
+ /* Get the type of the result. */
+ type = lookup_pointer_type (type);
+ val = value_from_long (builtin_type_long,
+ (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+ VALUE_TYPE (val) = type;
+ return val;
+}
+
+/* Return a pointer value for the object for which ARG1 is the contents. */
+
+value
+value_addr (arg1)
+ value arg1;
+{
+ register struct type *type;
+ register value val, arg1_coerced;
+
+ /* Taking the address of an array is really a no-op
+ once the array is coerced to a pointer to its first element. */
+ arg1_coerced = arg1;
+ COERCE_ARRAY (arg1_coerced);
+ if (arg1 != arg1_coerced)
+ return arg1_coerced;
+
+ if (VALUE_LVAL (arg1) != lval_memory)
+ error ("Attempt to take address of value not located in memory.");
+
+ /* Get the type of the result. */
+ type = lookup_pointer_type (VALUE_TYPE (arg1));
+ val = value_from_long (builtin_type_long,
+ (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+ VALUE_TYPE (val) = type;
+ return val;
+}
+
+/* Given a value of a pointer type, apply the C unary * operator to it. */
+
+value
+value_ind (arg1)
+ value arg1;
+{
+ /* Must do this before COERCE_ARRAY, otherwise an infinite loop
+ will result */
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF)
+ return value_at (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)),
+ (CORE_ADDR) value_as_long (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 (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)),
+ (CORE_ADDR) value_as_long (arg1));
+ else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF)
+ return value_at (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)),
+ (CORE_ADDR) value_as_long (arg1));
+ error ("Attempt to take contents of a non-pointer value.");
+}
+
+/* Pushing small parts of stack frames. */
+
+/* Push one word (the size of object that a register holds). */
+
+CORE_ADDR
+push_word (sp, buffer)
+ CORE_ADDR sp;
+ REGISTER_TYPE buffer;
+{
+ register int len = sizeof (REGISTER_TYPE);
+
+#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. */
+
+CORE_ADDR
+value_push (sp, arg)
+ register CORE_ADDR sp;
+ value 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
+value_arg_coerce (arg)
+ value arg;
+{
+ register struct type *type;
+
+ COERCE_ENUM (arg);
+
+ type = VALUE_TYPE (arg);
+
+ if (TYPE_CODE (type) == TYPE_CODE_INT
+ && TYPE_LENGTH (type) < sizeof (int))
+ return value_cast (builtin_type_int, arg);
+
+ if (type == builtin_type_float)
+ return value_cast (builtin_type_double, arg);
+
+ return arg;
+}
+
+/* Push the value ARG, first coercing it as an argument
+ to a C function. */
+
+CORE_ADDR
+value_arg_push (sp, arg)
+ register CORE_ADDR sp;
+ value arg;
+{
+ return value_push (sp, value_arg_coerce (arg));
+}
+
+#ifdef NEW_CALL_FUNCTION
+
+int
+arg_stacklen(nargs, args)
+ int nargs;
+ value *args;
+{
+ int len = 0;
+
+ while (--nargs >= 0)
+ len += TYPE_LENGTH(VALUE_TYPE(value_arg_coerce(args[nargs])));
+
+ return len;
+}
+
+CORE_ADDR
+function_address(function, type)
+ value function;
+ struct type **type;
+{
+ register CORE_ADDR funaddr;
+ register struct type *ftype = VALUE_TYPE(function);
+ register enum type_code code = TYPE_CODE(ftype);
+
+ /*
+ * 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);
+ *type = TYPE_TARGET_TYPE(ftype);
+ } else if (code == TYPE_CODE_PTR) {
+ funaddr = value_as_long(function);
+ if (TYPE_CODE(TYPE_TARGET_TYPE(ftype)) == TYPE_CODE_FUNC
+ || TYPE_CODE(TYPE_TARGET_TYPE(ftype)) == TYPE_CODE_METHOD)
+ *type = TYPE_TARGET_TYPE(TYPE_TARGET_TYPE(ftype));
+ else
+ *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_long(value_addr(function));
+ else
+ /*
+ * Handle integer used as address of a
+ * function.
+ */
+ funaddr = value_as_long(function);
+
+ *type = builtin_type_int;
+ } else
+ error("Invalid data type for function to be called.");
+
+ return funaddr;
+}
+
+/* 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
+call_function(function, nargs, args)
+ value function;
+ int nargs;
+ value *args;
+{
+ register CORE_ADDR sp, pc;
+ struct type *value_type;
+ struct inferior_status inf_status;
+ struct cleanup *old_chain;
+ register CORE_ADDR funaddr;
+ int struct_return_bytes;
+ char retbuf[REGISTER_BYTES];
+
+ if (!have_inferior_p())
+ error("Cannot invoke functions if the inferior is not running.");
+
+ save_inferior_status(&inf_status, 1);
+ old_chain = make_cleanup(restore_inferior_status, &inf_status);
+
+ sp = read_register(SP_REGNUM);
+ funaddr = function_address(function, &value_type);
+ /*
+ * Are we returning a value using a structure return or a
+ * normal value return?
+ */
+ if (using_struct_return(function, funaddr, value_type))
+ struct_return_bytes = TYPE_LENGTH(value_type);
+ else
+ struct_return_bytes = 0;
+ /*
+ * Create a call sequence customized for this function and
+ * the number of arguments for it.
+ */
+ pc = setup_dummy(sp, funaddr, nargs, args,
+ struct_return_bytes, value_arg_push);
+
+ /*
+ * Execute the stack dummy stub. The register state will be
+ * returned in retbuf. It is restored below.
+ */
+ run_stack_dummy(pc, retbuf);
+
+ /*
+ * This will restore the register context that existed before
+ * we called the dummy function.
+ */
+ do_cleanups(old_chain);
+
+ return value_being_returned(value_type, retbuf, struct_return_bytes);
+}
+#else
+
+/* 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
+call_function (function, nargs, args)
+ value function;
+ int nargs;
+ value *args;
+{
+ register CORE_ADDR sp;
+ register int i;
+ CORE_ADDR start_sp;
+ static REGISTER_TYPE dummy[] = CALL_DUMMY;
+ REGISTER_TYPE dummy1[sizeof dummy / sizeof (REGISTER_TYPE)];
+ 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;
+
+ if (!have_inferior_p ())
+ error ("Cannot invoke functions if the inferior is not running.");
+
+ 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_register (SP_REGNUM);
+
+#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
+
+ {
+ register CORE_ADDR funaddr;
+ register struct type *ftype = VALUE_TYPE (function);
+ register enum type_code code = TYPE_CODE (ftype);
+
+ /* 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_long (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_long (value_addr (function));
+ else
+ /* Handle integer used as address of a function. */
+ funaddr = value_as_long (function);
+
+ value_type = builtin_type_int;
+ }
+ else
+ error ("Invalid data type for function to be called.");
+
+ /* Are we returning a value using a structure return or a normal
+ value return? */
+
+ struct_return = using_struct_return (function, funaddr, value_type);
+
+ /* Create a call sequence customized for this function
+ and the number of arguments for it. */
+ bcopy (dummy, dummy1, sizeof dummy);
+ FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, value_type);
+ }
+
+#ifndef CANNOT_EXECUTE_STACK
+ write_memory (start_sp, dummy1, sizeof dummy);
+
+#else
+ /* 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;
+ start_sp = text_end - sizeof dummy;
+ write_memory (start_sp, dummy1, sizeof dummy);
+ }
+#endif /* CANNOT_EXECUTE_STACK */
+#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
+ }
+
+ for (i = nargs - 1; i >= 0; i--)
+ sp = value_arg_push (sp, args[i]);
+
+#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 this
+ convention in a slightly twisted way also. */
+
+ if (struct_return)
+ STORE_STRUCT_RETURN (struct_addr, sp);
+
+ /* Write the stack pointer. This is here because the statement above
+ might fool with it */
+ write_register (SP_REGNUM, sp);
+
+ /* Figure out the value returned by the function. */
+ {
+ char retbuf[REGISTER_BYTES];
+
+ /* Execute the stack dummy routine, calling FUNCTION.
+ When it is done, discard the empty frame
+ after storing the contents of all regs into retbuf. */
+ run_stack_dummy (start_sp + CALL_DUMMY_START_OFFSET, retbuf);
+
+ do_cleanups (old_chain);
+
+ return value_being_returned (value_type, retbuf, struct_return);
+ }
+}
+#endif
+
+/* Create a value for a string constant:
+ Call the function malloc in the inferior to get space for it,
+ then copy the data into that space
+ and then return the address with type char *.
+ PTR points to the string constant data; LEN is number of characters. */
+
+value
+value_string (ptr, len)
+ char *ptr;
+ int len;
+{
+ register value val;
+ register struct symbol *sym;
+ value blocklen;
+ register char *copy = (char *) alloca (len + 1);
+ char *i = ptr;
+ register char *o = copy, *ibeg = ptr;
+ register int c;
+#ifdef KERNELDEBUG
+ extern int kernel_debugging;
+
+ if (kernel_debugging)
+ error("Can't stuff string constants into kernel (yet).");
+#endif
+
+ /* Copy the string into COPY, processing escapes.
+ We could not conveniently process them in expread
+ because the string there wants to be a substring of the input. */
+
+ while (i - ibeg < len)
+ {
+ c = *i++;
+ if (c == '\\')
+ {
+ c = parse_escape (&i);
+ if (c == -1)
+ continue;
+ }
+ *o++ = c;
+ }
+ *o = 0;
+
+ /* Get the length of the string after escapes are processed. */
+
+ len = o - copy;
+
+ /* Find the address of malloc in the inferior. */
+
+ sym = lookup_symbol ("malloc", 0, VAR_NAMESPACE, 0);
+ if (sym != 0)
+ {
+ if (SYMBOL_CLASS (sym) != LOC_BLOCK)
+ error ("\"malloc\" exists in this program but is not a function.");
+ val = value_of_variable (sym);
+ }
+ else
+ {
+ register int i;
+ for (i = 0; i < misc_function_count; i++)
+ if (!strcmp (misc_function_vector[i].name, "malloc"))
+ break;
+ if (i < misc_function_count)
+ val = value_from_long (builtin_type_long,
+ (LONGEST) misc_function_vector[i].address);
+ else
+ error ("String constants require the program to have a function \"malloc\".");
+ }
+
+ blocklen = value_from_long (builtin_type_int, (LONGEST) (len + 1));
+ val = call_function (val, 1, &blocklen);
+ if (value_zerop (val))
+ error ("No memory available for string constant.");
+ write_memory ((CORE_ADDR) value_as_long (val), copy, len + 1);
+ VALUE_TYPE (val) = lookup_pointer_type (builtin_type_char);
+ return val;
+}
+
+static int
+type_field_index(t, name)
+ register struct type *t;
+ register char *name;
+{
+ register int i;
+
+ for (i = TYPE_NFIELDS(t); --i >= 0;)
+ {
+ register char *t_field_name = TYPE_FIELD_NAME (t, i);
+
+ if (t_field_name && !strcmp (t_field_name, name))
+ break;
+ }
+ return (i);
+}
+
+/* Given ARG1, 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 ARG1'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.
+
+ ERR is an error message to be printed in case the field is not found. */
+
+value
+value_struct_elt (arg1, args, name, static_memfuncp, err)
+ register value arg1, *args;
+ char *name;
+ int *static_memfuncp;
+ char *err;
+{
+ register struct type *t;
+ register int i;
+ int found = 0;
+
+ struct type *baseclass;
+
+ COERCE_ARRAY (arg1);
+
+ t = VALUE_TYPE (arg1);
+
+ /* Check for the usual case: we have pointer, target type is a struct
+ * and `name' is a legal field of the struct. In this case, we can
+ * just snarf the value of the field & not waste time while value_ind
+ * sucks over the entire struct. */
+ if (! args)
+ {
+ if (TYPE_CODE(t) == TYPE_CODE_PTR
+ && (TYPE_CODE((baseclass = TYPE_TARGET_TYPE(t))) == TYPE_CODE_STRUCT
+ || TYPE_CODE(baseclass) == TYPE_CODE_UNION)
+ && (i = type_field_index(baseclass, name)) >= 0)
+ {
+ register int offset;
+ register struct type *f = TYPE_FIELD_TYPE(baseclass, i);
+
+ offset = TYPE_FIELD_BITPOS(baseclass, i) >> 3;
+ if (TYPE_FIELD_BITSIZE(baseclass, i) == 0)
+ return value_at(f, (CORE_ADDR)(value_as_long(arg1) + offset));
+ }
+ }
+
+ /* Follow pointers until we get to a non-pointer. */
+
+ while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
+ {
+ arg1 = value_ind (arg1);
+ COERCE_ARRAY (arg1);
+ t = VALUE_TYPE (arg1);
+ }
+
+ 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);
+
+ baseclass = t;
+
+ /* 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 variable first, because if we succeed, there
+ is less work to be done. */
+ while (t)
+ {
+ i = type_field_index(t, name);
+ if (i >= 0)
+ return TYPE_FIELD_STATIC (t, i)
+ ? value_static_field (t, name, i) : value_field (arg1, i);
+
+ if (TYPE_N_BASECLASSES (t) == 0)
+ break;
+
+ t = TYPE_BASECLASS (t, 1);
+ VALUE_TYPE (arg1) = t; /* side effect! */
+ }
+
+ /* C++: If it was not found as a data field, then try to
+ return it as a pointer to a method. */
+ t = baseclass;
+ VALUE_TYPE (arg1) = t; /* side effect! */
+
+ if (destructor_name_p (name, t))
+ error ("use `info method' command to print out value of destructor");
+
+ while (t)
+ {
+ for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i)
+ {
+ if (! strcmp (TYPE_FN_FIELDLIST_NAME (t, i), name))
+ {
+ error ("use `info method' command to print value of method \"%s\"", name);
+ }
+ }
+
+ if (TYPE_N_BASECLASSES (t) == 0)
+ break;
+
+ t = TYPE_BASECLASS (t, 1);
+ }
+
+ error ("There is no field named %s.", name);
+ return 0;
+ }
+
+ if (destructor_name_p (name, t))
+ {
+ if (!args[1])
+ {
+ /* destructors are a special case. */
+ return (value)value_fn_field (arg1, 0,
+ TYPE_FN_FIELDLIST_LENGTH (t, 0));
+ }
+ else
+ {
+ error ("destructor should not have any argument");
+ }
+ }
+
+ /* This following loop is for methods with arguments. */
+ while (t)
+ {
+ /* Look up as method first, because that is where we
+ expect to find it first. */
+ for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; i--)
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i);
+
+ if (!strcmp (TYPE_FN_FIELDLIST_NAME (t, i), name))
+ {
+ int j;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i);
+
+ found = 1;
+ for (j = TYPE_FN_FIELDLIST_LENGTH (t, i) - 1; j >= 0; --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)value_virtual_fn_field (arg1, f, j, t);
+ if (TYPE_FN_FIELD_STATIC_P (f, j) && static_memfuncp)
+ *static_memfuncp = 1;
+ return (value)value_fn_field (arg1, i, j);
+ }
+ }
+ }
+
+ if (TYPE_N_BASECLASSES (t) == 0)
+ break;
+
+ t = TYPE_BASECLASS (t, 1);
+ VALUE_TYPE (arg1) = t; /* side effect! */
+ }
+
+ if (found)
+ {
+ error ("Structure method %s not defined for arglist.", name);
+ return 0;
+ }
+ else
+ {
+ /* See if user tried to invoke data as function */
+ t = baseclass;
+ while (t)
+ {
+ i = type_field_index(t, name);
+ if (i >= 0)
+ return TYPE_FIELD_STATIC (t, i)
+ ? value_static_field (t, name, i) : value_field (arg1, i);
+
+ if (TYPE_N_BASECLASSES (t) == 0)
+ break;
+
+ t = TYPE_BASECLASS (t, 1);
+ VALUE_TYPE (arg1) = t; /* side effect! */
+ }
+ error ("Structure has no component named %s.", name);
+ }
+}
+
+/* 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)
+ char *name;
+ struct type *type;
+{
+ /* destructors are a special case. */
+ char *dname = TYPE_NAME (type);
+
+ if (name[0] == '~')
+ {
+ if (! TYPE_HAS_DESTRUCTOR (type))
+ error ("type `%s' does not have destructor defined",
+ TYPE_NAME (type));
+ /* Skip past the "struct " at the front. */
+ while (*dname++ != ' ') ;
+ if (strcmp (dname, name+1))
+ error ("destructor specification error");
+ else
+ 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 arg1;
+ char *name;
+{
+ register struct type *t;
+ register int i;
+ int found = 0;
+
+ struct type *baseclass;
+
+ 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");
+
+ baseclass = t;
+
+ while (t)
+ {
+ for (i = TYPE_NFIELDS (t) - 1; i >= 0; i--)
+ {
+ char *t_field_name = TYPE_FIELD_NAME (t, i);
+ if (t_field_name && !strcmp (t_field_name, name))
+ goto success;
+ }
+ if (TYPE_N_BASECLASSES (t) == 0)
+ break;
+
+ t = TYPE_BASECLASS (t, 1);
+ VALUE_TYPE (arg1) = t; /* side effect! */
+ }
+
+ /* C++: If it was not found as a data field, then try to
+ return it as a pointer to a method. */
+ t = baseclass;
+
+ /* Destructors are a special case. */
+ if (destructor_name_p (name, t))
+ goto success;
+
+ while (t)
+ {
+ for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i)
+ {
+ if (!strcmp (TYPE_FN_FIELDLIST_NAME (t, i), name))
+ return 1;
+ }
+
+ if (TYPE_N_BASECLASSES (t) == 0)
+ break;
+
+ t = TYPE_BASECLASS (t, 1);
+ }
+ return 0;
+
+ success:
+ t = VALUE_TYPE (arg1);
+ while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
+ {
+ arg1 = value_ind (arg1);
+ COERCE_ARRAY (arg1);
+ t = VALUE_TYPE (arg1);
+ }
+}
+
+/* C++: Given an aggregate type DOMAIN, 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. */
+
+value
+value_struct_elt_for_address (domain, intype, name)
+ struct type *domain, *intype;
+ char *name;
+{
+ register struct type *t = domain;
+ register int i;
+ int found = 0;
+ value v;
+
+ struct type *baseclass;
+
+ if (TYPE_CODE (t) != TYPE_CODE_STRUCT
+ && TYPE_CODE (t) != TYPE_CODE_UNION)
+ error ("Internal error: non-aggregate type to value_struct_elt_for_address");
+
+ baseclass = t;
+
+ while (t)
+ {
+ for (i = TYPE_NFIELDS (t) - 1; i >= 0; i--)
+ {
+ char *t_field_name = TYPE_FIELD_NAME (t, i);
+ if (t_field_name && !strcmp (t_field_name, name))
+ {
+ if (TYPE_FIELD_PACKED (t, i))
+ error ("pointers to bitfield members not allowed");
+
+ v = value_from_long (builtin_type_int,
+ (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3));
+ VALUE_TYPE (v) = lookup_pointer_type (
+ lookup_member_type (TYPE_FIELD_TYPE (t, i), baseclass));
+ return v;
+ }
+ }
+
+ if (TYPE_N_BASECLASSES (t) == 0)
+ break;
+
+ t = TYPE_BASECLASS (t, 1);
+ }
+
+ /* C++: If it was not found as a data field, then try to
+ return it as a pointer to a method. */
+ t = baseclass;
+
+ /* Destructors are a special case. */
+ if (destructor_name_p (name, t))
+ {
+ error ("pointers to destructors not implemented yet");
+ }
+
+ /* Perform all necessary dereferencing. */
+ while (intype && TYPE_CODE (intype) == TYPE_CODE_PTR)
+ intype = TYPE_TARGET_TYPE (intype);
+
+ while (t)
+ {
+ for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i)
+ {
+ if (!strcmp (TYPE_FN_FIELDLIST_NAME (t, i), 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_VIRTUAL_P (f, j))
+ {
+ v = value_from_long (builtin_type_long,
+ (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j));
+ }
+ else
+ {
+ struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j),
+ 0, VAR_NAMESPACE, 0);
+ v = locate_var_value (s, 0);
+ }
+ VALUE_TYPE (v) = lookup_pointer_type (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j), baseclass));
+ return v;
+ }
+ }
+
+ if (TYPE_N_BASECLASSES (t) == 0)
+ break;
+
+ t = TYPE_BASECLASS (t, 1);
+ }
+ return 0;
+}
+
+/* Compare two argument lists and return the position in which they differ,
+ or zero if equal.
+
+ 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? */
+
+int
+typecmp (staticp, t1, t2)
+ int staticp;
+ struct type *t1[];
+ value t2[];
+{
+ int i;
+
+ if (staticp && t1 == 0)
+ return t2[1] != 0;
+ if (t1 == 0)
+ return 1;
+ if (t1[0]->code == TYPE_CODE_VOID) return 0;
+ if (t1[!staticp] == 0) return 0;
+ for (i = !staticp; t1[i] && t1[i]->code != TYPE_CODE_VOID; i++)
+ {
+ if (! t2[i]
+ || t1[i]->code != t2[i]->type->code
+ || t1[i]->target_type != t2[i]->type->target_type)
+ return i+1;
+ }
+ if (!t1[i]) return 0;
+ return t2[i] ? i+1 : 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
+value_of_this (complain)
+ int complain;
+{
+ extern FRAME selected_frame;
+ struct symbol *func, *sym;
+ char *funname = 0;
+ struct block *b;
+ int i;
+
+ if (selected_frame == 0)
+ if (complain)
+ error ("no frame selected");
+ else return 0;
+
+ func = get_frame_function (selected_frame);
+ if (func)
+ funname = SYMBOL_NAME (func);
+ else
+ 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;
+
+ sym = BLOCK_SYM (b, 0);
+ if (strncmp ("$this", SYMBOL_NAME (sym), 5))
+ if (complain)
+ error ("current stack frame not in method");
+ else return 0;
+
+ return read_var_value (sym, selected_frame);
+}
diff --git a/gnu/usr.bin/gdb/valprint.c b/gnu/usr.bin/gdb/valprint.c
new file mode 100644
index 0000000..781eb29
--- /dev/null
+++ b/gnu/usr.bin/gdb/valprint.c
@@ -0,0 +1,1430 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)valprint.c 6.5 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Print values for GNU debugger gdb.
+ Copyright (C) 1986, 1988, 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. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "value.h"
+
+/* GNU software is only expected to run on systems with 32-bit integers. */
+#define UINT_MAX 0xffffffff
+
+/* Maximum number of chars to print for a string pointer value
+ or vector contents, or UINT_MAX for no limit. */
+
+static unsigned int print_max;
+
+static void type_print_varspec_suffix ();
+static void type_print_varspec_prefix ();
+static void type_print_base ();
+static void type_print_method_args ();
+
+
+char **unsigned_type_table;
+char **signed_type_table;
+char **float_type_table;
+
+
+/* Print repeat counts if there are more than this
+ many repetitions of an element in an array. */
+#define REPEAT_COUNT_THRESHOLD 10
+
+/* 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. */
+
+void
+print_string (stream, string, length, force_ellipses)
+ 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;
+
+ if (length == 0)
+ {
+ fputs_filtered ("\"\"", 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 repititions 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)
+ {
+ fputs_filtered ("\", ", stream);
+ in_quotes = 0;
+ }
+ fputs_filtered ("'", stream);
+ 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)
+ {
+ fputs_filtered ("\"", stream);
+ in_quotes = 1;
+ }
+ printchar (string[i], stream, '"');
+ ++things_printed;
+ }
+ }
+
+ /* Terminate the quotes if necessary. */
+ if (in_quotes)
+ fputs_filtered ("\"", stream);
+
+ if (force_ellipses || i < length)
+ fputs_filtered ("...", stream);
+}
+
+/* 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 val;
+ FILE *stream;
+ char format;
+ enum val_prettyprint pretty;
+{
+ register unsigned int i, n, typelen;
+
+ /* 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))
+ {
+ n = VALUE_REPETITIONS (val);
+ 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)
+ print_string (stream, VALUE_CONTENTS (val), n, 0);
+ else
+ {
+ unsigned int things_printed = 0;
+
+ for (i = 0; i < n && things_printed < print_max; i++)
+ {
+ /* Position of the array element we are examining to see
+ whether it is repeated. */
+ unsigned int rep1;
+ /* Number of repititions we have detected so far. */
+ unsigned int reps;
+
+ if (i != 0)
+ fprintf_filtered (stream, ", ");
+
+ rep1 = i + 1;
+ reps = 1;
+ while (rep1 < n
+ && !bcmp (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 (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, "...");
+ }
+ fprintf_filtered (stream, "}");
+ return n * typelen;
+ }
+ else
+ {
+ /* 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 (VALUE_TYPE (val)) == TYPE_CODE_PTR
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_REF)
+ {
+ fprintf_filtered (stream, "(");
+ type_print (VALUE_TYPE (val), "", stream, -1);
+ fprintf_filtered (stream, ") ");
+
+ /* If this is a function pointer, try to print what
+ function it is pointing to by name. */
+ if (TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (val)))
+ == TYPE_CODE_FUNC)
+ {
+ print_address (((int *) VALUE_CONTENTS (val))[0], stream);
+ /* Return value is irrelevant except for string pointers. */
+ return 0;
+ }
+ }
+ return val_print (VALUE_TYPE (val), VALUE_CONTENTS (val),
+ VALUE_ADDRESS (val), stream, format, 1, 0, pretty);
+ }
+}
+
+static int prettyprint; /* Controls prettyprinting of structures. */
+int unionprint; /* Controls printing of nested unions. */
+static void scalar_print_hack();
+void (*default_scalar_print)() = scalar_print_hack;
+
+/* 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).
+
+ If the data are a string pointer, returns the number of
+ sting characters printed.
+
+ if DEREF_REF is nonzero, then dereference references,
+ otherwise just print them like pointers.
+
+ The PRETTY parameter controls prettyprinting. */
+
+int
+val_print (type, valaddr, address, stream, format,
+ deref_ref, recurse, pretty)
+ struct type *type;
+ char *valaddr;
+ CORE_ADDR address;
+ FILE *stream;
+ char format;
+ int deref_ref;
+ int recurse;
+ enum val_prettyprint pretty;
+{
+ register unsigned int i;
+ int len, n_baseclasses;
+ struct type *elttype;
+ int eltlen;
+ LONGEST val;
+ unsigned char c;
+
+ if (pretty == Val_pretty_default)
+ {
+ pretty = prettyprint ? Val_prettyprint : Val_no_prettyprint;
+ }
+
+ QUIT;
+
+ if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+ {
+ fprintf_filtered (stream, "<Type not defined in this context>");
+ fflush (stream);
+ return 0;
+ }
+
+ 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;
+ fprintf_filtered (stream, "{");
+ /* For an array of chars, print with string syntax. */
+ if (eltlen == 1 && TYPE_CODE (elttype) == TYPE_CODE_INT
+ && format == 0)
+ print_string (stream, valaddr, len, 0);
+ else
+ {
+ unsigned int things_printed = 0;
+
+ for (i = 0; i < len && things_printed < print_max; i++)
+ {
+ /* Position of the array element we are examining to see
+ whether it is repeated. */
+ unsigned int rep1;
+ /* Number of repititions we have detected so far. */
+ unsigned int reps;
+
+ if (i > 0)
+ fprintf_filtered (stream, ", ");
+
+ rep1 = i + 1;
+ reps = 1;
+ while (rep1 < len
+ && !bcmp (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);
+ fprintf_filtered (stream, " <repeats %u times>", reps);
+ i = rep1 - 1;
+ things_printed += REPEAT_COUNT_THRESHOLD;
+ }
+ else
+ {
+ val_print (elttype, valaddr + i * eltlen,
+ 0, stream, format, deref_ref,
+ recurse + 1, pretty);
+ things_printed++;
+ }
+ }
+ if (i < len)
+ fprintf_filtered (stream, "...");
+ }
+ fprintf_filtered (stream, "}");
+ break;
+ }
+ /* Array of unspecified length: treat like pointer to first elt. */
+ valaddr = (char *) &address;
+
+ case TYPE_CODE_PTR:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD)
+ {
+ struct type *domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type));
+ struct type *target = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type));
+ struct fn_field *f;
+ int j, len2;
+ char *kind = "";
+
+ val = unpack_long (builtin_type_int, valaddr);
+ if (val < 128)
+ {
+ 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) == val)
+ {
+ kind = "virtual";
+ goto common;
+ }
+ }
+ }
+ }
+ else
+ {
+ struct symbol *sym = find_pc_function ((CORE_ADDR) val);
+ 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 (!strcmp (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
+ goto common;
+ }
+ }
+ }
+ common:
+ if (i < len)
+ {
+ fprintf_filtered (stream, "&");
+ type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (f, j), stream, 0, 0);
+ fprintf (stream, kind);
+ if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
+ && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$')
+ type_print_method_args
+ (TYPE_FN_FIELD_ARGS (f, j) + 1, "~",
+ TYPE_FN_FIELDLIST_NAME (domain, i), 0, stream);
+ else
+ type_print_method_args
+ (TYPE_FN_FIELD_ARGS (f, j), "",
+ TYPE_FN_FIELDLIST_NAME (domain, i), 0, stream);
+ break;
+ }
+ fprintf_filtered (stream, "(");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, ") %d", (int) val >> 3);
+ }
+ else if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER)
+ {
+ struct type *domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type));
+ struct type *target = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type));
+ char *kind = "";
+
+ /* 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;
+ len = TYPE_NFIELDS (domain);
+ /* @@ Make VAL into bit offset */
+ val = unpack_long (builtin_type_int, valaddr) << 3;
+ for (i = 0; i < len; i++)
+ {
+ int bitpos = TYPE_FIELD_BITPOS (domain, i);
+ QUIT;
+ if (val == bitpos)
+ break;
+ if (val < bitpos && i > 0)
+ {
+ int ptrsize = (TYPE_LENGTH (builtin_type_char) * TYPE_LENGTH (target));
+ /* Somehow pointing into a field. */
+ i -= 1;
+ extra = (val - TYPE_FIELD_BITPOS (domain, i));
+ if (extra & 0x3)
+ bits = 1;
+ else
+ extra >>= 3;
+ break;
+ }
+ }
+ if (i < len)
+ {
+ fprintf_filtered (stream, "&");
+ 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)");
+ break;
+ }
+ fprintf_filtered (stream, "%d", val >> 3);
+ }
+ else
+ {
+ fprintf_filtered (stream, "0x%x", * (int *) valaddr);
+ /* For a pointer to char or unsigned char,
+ also print the string pointed to, unless pointer is null. */
+
+ /* For an array of chars, print with string syntax. */
+ elttype = TYPE_TARGET_TYPE (type);
+ i = 0; /* Number of characters printed. */
+ if (TYPE_LENGTH (elttype) == 1
+ && TYPE_CODE (elttype) == TYPE_CODE_INT
+ && format == 0
+ && unpack_long (type, valaddr) != 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)
+ {
+ fprintf_filtered (stream, " ");
+
+ /* Get first character. */
+ if (read_memory ( (CORE_ADDR) unpack_long (type, valaddr),
+ &c, 1))
+ {
+ /* First address out of bounds. */
+ fprintf_filtered (stream, "<Address 0x%x out of bounds>",
+ (* (int *) valaddr));
+ break;
+ }
+ else
+ {
+ /* A real string. */
+ int out_of_bounds = 0;
+ char *string = (char *) alloca (print_max);
+
+ /* If the loop ends by us hitting print_max characters,
+ we need to have elipses at the end. */
+ int force_ellipses = 1;
+
+ /* This loop only fetches print_max characters, even
+ though print_string might want to print more
+ (with repeated characters). This is so that
+ we don't spend forever fetching if we print
+ a long string consisting of the same character
+ repeated. */
+ while (i < print_max)
+ {
+ QUIT;
+ if (read_memory ((CORE_ADDR) unpack_long (type, valaddr)
+ + i, &c, 1))
+ {
+ out_of_bounds = 1;
+ force_ellipses = 0;
+ break;
+ }
+ else if (c == '\0')
+ {
+ force_ellipses = 0;
+ break;
+ }
+ else
+ string[i++] = c;
+ }
+
+ if (i != 0)
+ print_string (stream, string, i, force_ellipses);
+ if (out_of_bounds)
+ fprintf_filtered (stream,
+ " <Address 0x%x out of bounds>",
+ (*(int *) valaddr) + i);
+ }
+
+ fflush (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_MEMBER:
+ error ("not implemented: member type in val_print");
+ break;
+
+ case TYPE_CODE_REF:
+ fprintf_filtered (stream, "(0x%x &) = ", * (int *) valaddr);
+ /* De-reference the reference. */
+ if (deref_ref)
+ {
+ if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_UNDEF)
+ {
+ value val = value_at (TYPE_TARGET_TYPE (type), * (int *) valaddr);
+ val_print (VALUE_TYPE (val), VALUE_CONTENTS (val),
+ VALUE_ADDRESS (val), stream, format,
+ deref_ref, recurse + 1, pretty);
+ }
+ else
+ fprintf_filtered (stream, "???");
+ }
+ break;
+
+ case TYPE_CODE_UNION:
+ if (recurse && !unionprint)
+ {
+ fprintf_filtered (stream, "{...}");
+ break;
+ }
+ /* Fall through. */
+ case TYPE_CODE_STRUCT:
+ fprintf_filtered (stream, "{");
+ len = TYPE_NFIELDS (type);
+ n_baseclasses = TYPE_N_BASECLASSES (type);
+ for (i = 1; i <= n_baseclasses; i++)
+ {
+ fprintf_filtered (stream, "\n");
+ if (pretty)
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ fputs_filtered ("<", stream);
+ fputs_filtered (TYPE_NAME (TYPE_BASECLASS (type, i)), stream);
+ fputs_filtered ("> = ", stream);
+ val_print (TYPE_FIELD_TYPE (type, 0),
+ valaddr + TYPE_FIELD_BITPOS (type, i-1) / 8,
+ 0, stream, 0, 0, recurse + 1, pretty);
+ }
+ if (i > 1) {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ fputs_filtered ("members of ", stream);
+ fputs_filtered (TYPE_NAME (type), stream);
+ fputs_filtered (": ", stream);
+ }
+ if (!len && i == 1)
+ fprintf_filtered (stream, "<No data fields>");
+ else
+ {
+ for (i -= 1; i < len; i++)
+ {
+ if (i > n_baseclasses) fprintf_filtered (stream, ", ");
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 + 2 * recurse, stream);
+ }
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+ fputs_filtered (" = ", stream);
+ /* check if static field */
+ if (TYPE_FIELD_STATIC (type, i))
+ {
+ value v;
+
+ v = value_static_field (type, TYPE_FIELD_NAME (type, i), i);
+ val_print (TYPE_FIELD_TYPE (type, i),
+ VALUE_CONTENTS (v), 0, stream, format,
+ deref_ref, recurse + 1, pretty);
+ }
+ else if (TYPE_FIELD_PACKED (type, i))
+ {
+ char *valp = (char *) & val;
+ union {int i; char c;} test;
+ test.i = 1;
+ if (test.c != 1)
+ valp += sizeof val - TYPE_LENGTH (TYPE_FIELD_TYPE (type, i));
+ val = unpack_field_as_long (type, valaddr, i);
+ val_print (TYPE_FIELD_TYPE (type, i), valp, 0,
+ stream, format, deref_ref, recurse + 1, pretty);
+ }
+ else
+ {
+ val_print (TYPE_FIELD_TYPE (type, i),
+ valaddr + TYPE_FIELD_BITPOS (type, i) / 8,
+ 0, stream, format, deref_ref,
+ recurse + 1, pretty);
+ }
+ }
+ if (pretty)
+ {
+ fprintf_filtered (stream, "\n");
+ print_spaces_filtered (2 * recurse, stream);
+ }
+ }
+ fprintf_filtered (stream, "}");
+ break;
+
+ case TYPE_CODE_ENUM:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ len = TYPE_NFIELDS (type);
+ val = unpack_long (builtin_type_int, 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
+ fprintf_filtered (stream, "%d", (int) val);
+ break;
+
+ case TYPE_CODE_FUNC:
+ if (format)
+ {
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ break;
+ }
+ fprintf_filtered (stream, "{");
+ type_print (type, "", stream, -1);
+ fprintf_filtered (stream, "} ");
+ fprintf_filtered (stream, "0x%x", address);
+ break;
+
+ case TYPE_CODE_INT:
+ if (format)
+ print_scalar_formatted (valaddr, type, format, 0, stream);
+ else
+ {
+ (*default_scalar_print)(stream, type, unpack_long(type, valaddr));
+#ifdef notdef
+ if (TYPE_LENGTH (type) == 1)
+ {
+ fprintf_filtered (stream, " '");
+ printchar ((unsigned char) unpack_long (type, valaddr),
+ stream, '\'');
+ fprintf_filtered (stream, "'");
+ }
+#endif
+ }
+ 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;
+
+ default:
+ error ("Invalid type code in symbol table.");
+ }
+ fflush (stream);
+ return 0;
+}
+
+/* Print a description of a type TYPE
+ in the form of a declaration of a variable named VARSTRING.
+ 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;
+ FILE *stream;
+ int show;
+{
+ type_print_1 (type, varstring, stream, show, 0);
+}
+
+/* LEVEL is the depth to indent lines by. */
+
+void
+type_print_1 (type, varstring, stream, show, level)
+ struct type *type;
+ char *varstring;
+ FILE *stream;
+ int show;
+ int level;
+{
+ register enum type_code code;
+ type_print_base (type, stream, show, level);
+ code = TYPE_CODE (type);
+ if ((varstring && *varstring)
+ ||
+ /* 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)))
+ fprintf_filtered (stream, " ");
+ type_print_varspec_prefix (type, stream, show, 0);
+ fputs_filtered (varstring, stream);
+ type_print_varspec_suffix (type, stream, show, 0);
+}
+
+/* Print the method arguments ARGS to the file STREAM. */
+static void
+type_print_method_args (args, prefix, varstring, staticp, stream)
+ struct type **args;
+ char *prefix, *varstring;
+ int staticp;
+ FILE *stream;
+{
+ int i;
+
+ fputs_filtered (" ", stream);
+ fputs_filtered (prefix, stream);
+ fputs_filtered (varstring, stream);
+ 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 out all layers of the type heirarchy
+ until we encounter one with multiple inheritance.
+ At that point, print out that ply, and return. */
+static void
+type_print_derivation_info (stream, type)
+ FILE *stream;
+ struct type *type;
+{
+ char *name;
+ int i, n_baseclasses = TYPE_N_BASECLASSES (type);
+ struct type *basetype = 0;
+
+ while (type && n_baseclasses == 1)
+ {
+ basetype = TYPE_BASECLASS (type, 1);
+ if (TYPE_NAME (basetype) && (name = TYPE_NAME (basetype)))
+ {
+ while (*name != ' ') name++;
+ fprintf_filtered (stream, ": %s%s ",
+ TYPE_VIA_PUBLIC (basetype) ? "public" : "private",
+ TYPE_VIA_VIRTUAL (basetype) ? " virtual" : "");
+ fputs_filtered (name + 1, stream);
+ fputs_filtered (" ", stream);
+ }
+ n_baseclasses = TYPE_N_BASECLASSES (basetype);
+ type = basetype;
+ }
+
+ if (type)
+ {
+ if (n_baseclasses != 0)
+ fprintf_filtered (stream, ": ");
+ for (i = 1; i <= n_baseclasses; i++)
+ {
+ basetype = TYPE_BASECLASS (type, i);
+ if (TYPE_NAME (basetype) && (name = TYPE_NAME (basetype)))
+ {
+ while (*name != ' ') name++;
+ fprintf_filtered (stream, "%s%s ",
+ TYPE_VIA_PUBLIC (basetype) ? "public" : "private",
+ TYPE_VIA_VIRTUAL (basetype) ? " virtual" : "");
+ fputs_filtered (name + 1, stream);
+ }
+ if (i < n_baseclasses)
+ fprintf_filtered (stream, ", ");
+ }
+ fprintf_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. */
+
+static void
+type_print_varspec_prefix (type, stream, show, passed_a_ptr)
+ struct type *type;
+ FILE *stream;
+ int show;
+ int passed_a_ptr;
+{
+ if (type == 0)
+ return;
+
+ if (TYPE_NAME (type) && show <= 0)
+ return;
+
+ QUIT;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_PTR:
+ 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, "(");
+ type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
+ 0);
+ fprintf_filtered (stream, " ");
+ 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 (stream, "(");
+ type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
+ 0);
+ fprintf_filtered (stream, " ");
+ type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0,
+ passed_a_ptr);
+ fprintf_filtered (stream, "::");
+ break;
+
+ case TYPE_CODE_REF:
+ type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+ fprintf_filtered (stream, "&");
+ break;
+
+ case TYPE_CODE_FUNC:
+ type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
+ 0);
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+ break;
+
+ case TYPE_CODE_ARRAY:
+ type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
+ 0);
+ if (passed_a_ptr)
+ fprintf_filtered (stream, "(");
+ }
+}
+
+/* Print any array sizes, function arguments or close parentheses
+ needed after the variable name (to describe its type).
+ Args work like type_print_varspec_prefix. */
+
+static void
+type_print_varspec_suffix (type, stream, show, passed_a_ptr)
+ struct type *type;
+ FILE *stream;
+ int show;
+ int passed_a_ptr;
+{
+ 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, "]");
+
+ type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
+ 0);
+ break;
+
+ case TYPE_CODE_MEMBER:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ break;
+
+ case TYPE_CODE_METHOD:
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+ if (passed_a_ptr)
+ {
+ int i;
+ struct type **args = TYPE_ARG_TYPES (type);
+
+ fprintf_filtered (stream, "(");
+ if (args[1] == 0)
+ fprintf_filtered (stream, "...");
+ else for (i = 1; args[i] != 0 && args[i]->code != TYPE_CODE_VOID; i++)
+ {
+ type_print_1 (args[i], "", stream, -1, 0);
+ if (args[i+1] == 0)
+ fprintf_filtered (stream, "...");
+ else if (args[i+1]->code != TYPE_CODE_VOID)
+ fprintf_filtered (stream, ",");
+ }
+ fprintf_filtered (stream, ")");
+ }
+ break;
+
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_REF:
+ type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+ break;
+
+ case TYPE_CODE_FUNC:
+ type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
+ passed_a_ptr);
+ if (passed_a_ptr)
+ fprintf_filtered (stream, ")");
+ fprintf_filtered (stream, "()");
+ 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 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 struct 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
+type_print_base (type, stream, show, level)
+ struct type *type;
+ FILE *stream;
+ int show;
+ int level;
+{
+ char *name;
+ register int i;
+ register int len;
+ register int lastval;
+
+ QUIT;
+
+ if (type == 0)
+ {
+ fprintf_filtered (stream, "type unknown");
+ return;
+ }
+
+ if (TYPE_NAME (type) && show <= 0)
+ {
+ fputs_filtered (TYPE_NAME (type), stream);
+ return;
+ }
+
+ 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:
+ type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ fprintf_filtered (stream, "struct ");
+ goto struct_union;
+
+ case TYPE_CODE_UNION:
+ fprintf_filtered (stream, "union ");
+ struct_union:
+ if (TYPE_NAME (type) && (name = TYPE_NAME (type)))
+ {
+ while (*name != ' ') name++;
+ fputs_filtered (name + 1, stream);
+ fputs_filtered (" ", stream);
+ }
+ if (show < 0)
+ fprintf_filtered (stream, "{...}");
+ else
+ {
+ int i;
+
+ type_print_derivation_info (stream, type);
+
+ fprintf_filtered (stream, "{");
+ len = TYPE_NFIELDS (type);
+ if (len)
+ fprintf_filtered (stream, "\n");
+ else
+ {
+ if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+ fprintf_filtered (stream, "<incomplete type>\n");
+ else
+ fprintf_filtered (stream, "<no data fields>\n");
+ }
+
+ /* If there is a base class for this type,
+ do not print the field that it occupies. */
+ for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+ {
+ QUIT;
+ /* Don't print out virtual function table. */
+ if (! strncmp (TYPE_FIELD_NAME (type, i),
+ "_vptr$", 6))
+ continue;
+
+ print_spaces_filtered (level + 4, stream);
+ if (TYPE_FIELD_STATIC (type, i))
+ {
+ fprintf_filtered (stream, "static ");
+ }
+ type_print_1 (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");
+ }
+
+ /* C++: print out the methods */
+ len = TYPE_NFN_FIELDS (type);
+ if (len) fprintf_filtered (stream, "\n");
+ for (i = 0; i < len; i++)
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+ int j, len2 = TYPE_FN_FIELDLIST_LENGTH (type, i);
+
+ for (j = 0; j < len2; j++)
+ {
+ QUIT;
+ 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 ");
+ type_print (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)), "", stream, 0);
+ if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
+ && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$')
+ type_print_method_args
+ (TYPE_FN_FIELD_ARGS (f, j) + 1, "~",
+ TYPE_FN_FIELDLIST_NAME (type, i), 0, stream);
+ else
+ type_print_method_args
+ (TYPE_FN_FIELD_ARGS (f, j), "",
+ TYPE_FN_FIELDLIST_NAME (type, i),
+ TYPE_FN_FIELD_STATIC_P (f, j), stream);
+
+ fprintf_filtered (stream, ";\n");
+ }
+ if (len2) fprintf_filtered (stream, "\n");
+ }
+
+ print_spaces_filtered (level, stream);
+ fprintf_filtered (stream, "}");
+ }
+ break;
+
+ case TYPE_CODE_ENUM:
+ fprintf_filtered (stream, "enum ");
+ if (TYPE_NAME (type))
+ {
+ name = TYPE_NAME (type);
+ while (*name != ' ') name++;
+ fputs_filtered (name + 1, stream);
+ fputs_filtered (" ", stream);
+ }
+ if (show < 0)
+ fprintf_filtered (stream, "{...}");
+ else
+ {
+ fprintf_filtered (stream, "{");
+ len = TYPE_NFIELDS (type);
+ lastval = 0;
+ for (i = 0; i < len; i++)
+ {
+ QUIT;
+ if (i) fprintf_filtered (stream, ", ");
+ 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_INT:
+ if (TYPE_UNSIGNED (type))
+ name = unsigned_type_table[TYPE_LENGTH (type)];
+ else
+ name = signed_type_table[TYPE_LENGTH (type)];
+ fputs_filtered (name, stream);
+ break;
+
+ case TYPE_CODE_FLT:
+ name = float_type_table[TYPE_LENGTH (type)];
+ fputs_filtered (name, stream);
+ break;
+
+ case TYPE_CODE_VOID:
+ fprintf_filtered (stream, "void");
+ break;
+
+ case 0:
+ fprintf_filtered (stream, "struct unknown");
+ break;
+
+ default:
+ error ("Invalid type code in symbol table.");
+ }
+}
+
+static void
+scalar_print_decimal(stream, type, val)
+ FILE *stream;
+ struct type *type;
+ LONGEST val;
+{
+ fprintf_filtered(stream, TYPE_UNSIGNED(type)? "%lu":"%ld", val);
+}
+
+static void
+scalar_print_hex(stream, type, val)
+ FILE *stream;
+ struct type *type;
+ LONGEST val;
+{
+ switch (TYPE_LENGTH(type)) {
+ case 1:
+ fprintf_filtered (stream, "0x%02lx", val);
+ break;
+ case 2:
+ fprintf_filtered (stream, "0x%04lx", val);
+ break;
+ case 4:
+ fprintf_filtered (stream, "0x%08lx", val);
+ break;
+ default:
+ fprintf_filtered (stream, "0x%lx", val);
+ break;
+ }
+}
+
+static void
+scalar_print_octal(stream, type, val)
+ FILE *stream;
+ struct type *type;
+ LONGEST val;
+{
+ switch (TYPE_LENGTH(type)) {
+ case 1:
+ fprintf_filtered (stream, "0%03lo", val);
+ break;
+ case 2:
+ fprintf_filtered (stream, "0%06lo", val);
+ break;
+ case 4:
+ fprintf_filtered (stream, "0%012lo", val);
+ break;
+ default:
+ fprintf_filtered (stream, "0%lo", val);
+ break;
+ }
+}
+
+static void
+scalar_print_hack(stream, type, val)
+ FILE *stream;
+ struct type *type;
+ LONGEST val;
+{
+ if (TYPE_UNSIGNED(type))
+ scalar_print_hex(stream, type, val);
+ else
+ scalar_print_decimal(stream, type, val);
+}
+
+static void
+set_maximum_command (arg)
+ char *arg;
+{
+ if (!arg) error_no_arg ("value for maximum elements to print");
+ print_max = parse_and_eval_address (arg);
+ if (print_max == 0)
+ print_max = UINT_MAX;
+}
+
+static void
+set_base_command(arg)
+ char *arg;
+{
+ int base;
+
+ if (!arg)
+ base = 0;
+ else
+ base = parse_and_eval_address (arg);
+ switch (base) {
+ default:
+ default_scalar_print = scalar_print_hack;
+ break;
+ case 8:
+ default_scalar_print = scalar_print_octal;
+ break;
+ case 10:
+ default_scalar_print = scalar_print_decimal;
+ break;
+ case 16:
+ default_scalar_print = scalar_print_hex;
+ break;
+ }
+}
+
+static void
+set_prettyprint_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ prettyprint = parse_binary_operation ("set prettyprint", arg);
+}
+
+static void
+set_unionprint_command (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ unionprint = parse_binary_operation ("set unionprint", arg);
+}
+
+format_info (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ if (arg)
+ error ("\"info format\" does not take any arguments.");
+ printf ("Prettyprinting of structures is %s.\n",
+ prettyprint ? "on" : "off");
+ printf ("Printing of unions interior to structures is %s.\n",
+ unionprint ? "on" : "off");
+ if (print_max == UINT_MAX)
+ printf_filtered
+ ("There is no maximum number of array elements printed.\n");
+ else
+ printf_filtered
+ ("The maximum number of array elements printed is %d.\n", print_max);
+}
+
+extern struct cmd_list_element *setlist;
+
+void
+_initialize_valprint ()
+{
+ add_cmd ("base", class_support, set_base_command,
+ "Change default integer print radix to 8, 10 or 16\n\
+No args returns to the ad-hoc default of `16' for unsigned values\n\
+and `10' otherwise.",
+ &setlist);
+ add_cmd ("array-max", class_vars, set_maximum_command,
+ "Set NUMBER as limit on string chars or array elements to print.\n\
+\"set array-max 0\" causes there to be no limit.",
+ &setlist);
+
+ add_cmd ("prettyprint", class_support, set_prettyprint_command,
+ "Turn prettyprinting of structures on and off.",
+ &setlist);
+ add_alias_cmd ("pp", "prettyprint", class_support, 1, &setlist);
+
+ add_cmd ("unionprint", class_support, set_unionprint_command,
+ "Turn printing of unions interior to structures on and off.",
+ &setlist);
+
+ add_info ("format", format_info,
+ "Show current settings of data formatting options.");
+
+ /* Give people the defaults which they are used to. */
+ prettyprint = 0;
+ unionprint = 1;
+
+ print_max = 200;
+
+ unsigned_type_table
+ = (char **) xmalloc ((1 + sizeof (unsigned LONGEST)) * sizeof (char *));
+ bzero (unsigned_type_table, (1 + sizeof (unsigned LONGEST)));
+ unsigned_type_table[sizeof (unsigned char)] = "unsigned char";
+ unsigned_type_table[sizeof (unsigned short)] = "unsigned short";
+ unsigned_type_table[sizeof (unsigned long)] = "unsigned long";
+ unsigned_type_table[sizeof (unsigned int)] = "unsigned int";
+#ifdef LONG_LONG
+ unsigned_type_table[sizeof (unsigned long long)] = "unsigned long long";
+#endif
+
+ signed_type_table
+ = (char **) xmalloc ((1 + sizeof (LONGEST)) * sizeof (char *));
+ bzero (signed_type_table, (1 + sizeof (LONGEST)));
+ signed_type_table[sizeof (char)] = "char";
+ signed_type_table[sizeof (short)] = "short";
+ signed_type_table[sizeof (long)] = "long";
+ signed_type_table[sizeof (int)] = "int";
+#ifdef LONG_LONG
+ signed_type_table[sizeof (long long)] = "long long";
+#endif
+
+ float_type_table
+ = (char **) xmalloc ((1 + sizeof (double)) * sizeof (char *));
+ bzero (float_type_table, (1 + sizeof (double)));
+ float_type_table[sizeof (float)] = "float";
+ float_type_table[sizeof (double)] = "double";
+}
+
diff --git a/gnu/usr.bin/gdb/value.h b/gnu/usr.bin/gdb/value.h
new file mode 100644
index 0000000..07dd8e8
--- /dev/null
+++ b/gnu/usr.bin/gdb/value.h
@@ -0,0 +1,212 @@
+/* Definitions for values of C expressions, for GDB.
+ 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. */
+
+/*
+ * 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;
+ /* Location of value (if lval). */
+ union
+ {
+ /* Address in inferior or byte of registers structure. */
+ CORE_ADDR address;
+ /* Pointer to interrnal 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. */
+ 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;
+ /* Actual contents of the value. For use of this value; setting
+ it uses the stuff above. */
+ long contents[1];
+ };
+
+typedef struct value *value;
+
+#define VALUE_TYPE(val) (val)->type
+#define VALUE_CONTENTS(val) ((char *) (val)->contents)
+#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
+
+/* If ARG is an array, convert it to a pointer.
+ If ARG is an enum, convert it to an integer.
+
+ References are dereferenced. */
+
+#define COERCE_ARRAY(arg) \
+{ if (TYPE_CODE ( VALUE_TYPE (arg)) == TYPE_CODE_REF) \
+ arg = value_ind (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_ENUM) \
+ arg = value_cast (builtin_type_unsigned_int, arg); \
+}
+
+/* If ARG is an enum, convert it to an integer. */
+
+#define COERCE_ENUM(arg) \
+{ if (TYPE_CODE ( VALUE_TYPE (arg)) == TYPE_CODE_REF) \
+ arg = value_ind (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 value;
+};
+
+LONGEST value_as_long ();
+double value_as_double ();
+LONGEST unpack_long ();
+double unpack_double ();
+long unpack_field_as_long ();
+value value_from_long ();
+value value_from_double ();
+value value_at ();
+value value_from_register ();
+value value_of_variable ();
+value value_of_register ();
+value read_var_value ();
+value locate_var_value ();
+value allocate_value ();
+value allocate_repeat_value ();
+value value_string ();
+
+value value_binop ();
+value value_add ();
+value value_sub ();
+value value_coerce_array ();
+value value_ind ();
+value value_addr ();
+value value_assign ();
+value value_neg ();
+value value_lognot ();
+value value_struct_elt (), value_struct_elt_for_address ();
+value value_field ();
+value value_cast ();
+value value_zero ();
+value value_repeat ();
+value value_subscript ();
+
+value call_function ();
+value value_being_returned ();
+int using_struct_return ();
+
+value evaluate_expression ();
+value evaluate_type ();
+value parse_and_eval ();
+value parse_to_comma_and_eval ();
+
+value access_value_history ();
+value value_of_internalvar ();
+struct internalvar *lookup_internalvar ();
+
+int value_equal ();
+int value_less ();
+int value_zerop ();
+
+/* C++ */
+value value_of_this ();
+value value_static_field ();
+value value_x_binop ();
+value value_x_unop ();
+int binop_user_defined_p ();
+int unop_user_defined_p ();
+
+void read_register_bytes ();
+void modify_field ();
+void type_print ();
+void type_print_1 ();
+
+/* Possibilities for prettyprint parameters to routines which print
+ things. */
+enum val_prettyprint {
+ Val_no_prettyprint = 0,
+ Val_prettyprint,
+ /* Use the default setting which the user has specified. */
+ Val_pretty_default
+ };
+
diff --git a/gnu/usr.bin/gdb/values.c b/gnu/usr.bin/gdb/values.c
new file mode 100644
index 0000000..93a2911
--- /dev/null
+++ b/gnu/usr.bin/gdb/values.c
@@ -0,0 +1,1059 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)values.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Low level packing and unpacking of values for GDB.
+ 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. */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "value.h"
+
+/* 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 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 all_values;
+
+/* Allocate a value that has the correct length for type TYPE. */
+
+value
+allocate_value (type)
+ struct type *type;
+{
+ register value val;
+
+ /* If the type we want had no definition in the file it first
+ * appeared in, it will be marked a `stub'. The real definition
+ * probably appeared later so try to find it. */
+ if (TYPE_FLAGS(type) & TYPE_FLAG_STUB)
+ {
+ register char *cp;
+ register struct symbol *sym;
+ extern char *index();
+
+ if (cp = index(TYPE_NAME(type), ' '))
+ ++cp;
+ else
+ cp = TYPE_NAME(type);
+
+ sym = lookup_symbol(cp, 0, STRUCT_NAMESPACE, 0);
+
+ if (sym && TYPE_CODE(SYMBOL_TYPE(sym)) == TYPE_CODE(type))
+ bcopy (SYMBOL_TYPE (sym), type, sizeof (*type));
+ }
+ val = (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;
+ return val;
+}
+
+/* Allocate a value that has the correct length
+ for COUNT repetitions type TYPE. */
+
+value
+allocate_repeat_value (type, count)
+ struct type *type;
+ int count;
+{
+ register value val;
+
+ val = (value) 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;
+ return 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 val, next;
+
+ for (val = all_values; val; val = next)
+ {
+ next = VALUE_NEXT (val);
+ 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 val;
+{
+ register value 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;
+ }
+ }
+}
+
+/* Return a copy of the value ARG.
+ It contains the same contents, for same memory address,
+ but it's a different block of storage. */
+
+static value
+value_copy (arg)
+ value arg;
+{
+ register value 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);
+ bcopy (VALUE_CONTENTS (arg), VALUE_CONTENTS (val),
+ 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. */
+
+int
+record_latest_value (val)
+ value val;
+{
+ int i;
+ double foo;
+
+ /* 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) {
+ foo = 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));
+ bzero (new->values, sizeof new->values);
+ new->next = value_history_chain;
+ value_history_chain = new;
+ }
+
+ value_history_chain->values[i] = val;
+ 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
+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 val;
+
+ while (value_history_chain)
+ {
+ for (i = 0; i < VALUE_HISTORY_CHUNK; i++)
+ if (val = value_history_chain->values[i])
+ free (val);
+ next = value_history_chain->next;
+ free (value_history_chain);
+ value_history_chain = next;
+ }
+ value_history_count = 0;
+}
+
+static void
+value_history_info (num_exp, from_tty)
+ char *num_exp;
+ int from_tty;
+{
+ register int i;
+ register value val;
+ static int num = 1;
+
+ if (num_exp)
+ {
+ if (num_exp[0] == '+' && num_exp[1] == '\0')
+ /* "info history +" should print from the stored position. */
+ ;
+ else
+ /* "info history <exp>" should print around value number <exp>. */
+ 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, 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 (!strcmp (var->name, name))
+ return var;
+
+ var = (struct internalvar *) xmalloc (sizeof (struct internalvar));
+ var->name = concat (name, "", "");
+ var->value = allocate_value (builtin_type_void);
+ release_value (var->value);
+ var->next = internalvars;
+ internalvars = var;
+ return var;
+}
+
+value
+value_of_internalvar (var)
+ struct internalvar *var;
+{
+ register value val;
+
+#ifdef IS_TRAPPED_INTERNALVAR
+ if (IS_TRAPPED_INTERNALVAR (var->name))
+ return VALUE_OF_TRAPPED_INTERNALVAR (var);
+#endif
+
+ val = value_copy (var->value);
+ 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 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, (int) value_as_long (newval),
+ bitpos, bitsize);
+ else
+ bcopy (VALUE_CONTENTS (newval), addr,
+ TYPE_LENGTH (VALUE_TYPE (newval)));
+}
+
+void
+set_internalvar (var, val)
+ struct internalvar *var;
+ value val;
+{
+#ifdef IS_TRAPPED_INTERNALVAR
+ if (IS_TRAPPED_INTERNALVAR (var->name))
+ SET_TRAPPED_INTERNALVAR (var, val, 0, 0, 0);
+#endif
+
+ free (var->value);
+ var->value = value_copy (val);
+ release_value (var->value);
+}
+
+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 (var->name);
+ free (var->value);
+ free (var);
+ }
+}
+
+static void
+convenience_info ()
+{
+ 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)
+ {
+ printf ("Debugger convenience variables:\n\n");
+ varseen = 1;
+ }
+ printf ("$%s: ", var->name);
+ value_print (var->value, stdout, 0, Val_pretty_default);
+ printf ("\n");
+ }
+ if (!varseen)
+ printf ("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 val;
+{
+ return unpack_long (VALUE_TYPE (val), VALUE_CONTENTS (val));
+}
+
+double
+value_as_double (val)
+ register value 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;
+}
+
+/* Unpack raw data (copied from debugee) 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.
+
+ 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);
+
+ if (code == TYPE_CODE_ENUM)
+ code = TYPE_CODE_INT;
+ if (code == TYPE_CODE_FLT)
+ {
+ if (len == sizeof (float))
+ return * (float *) valaddr;
+
+ if (len == sizeof (double))
+ return * (double *) valaddr;
+ }
+ else if (code == TYPE_CODE_INT && nosign)
+ {
+ if (len == sizeof (char))
+ return * (unsigned char *) valaddr;
+
+ if (len == sizeof (short))
+ return * (unsigned short *) valaddr;
+
+ if (len == sizeof (int))
+ return * (unsigned int *) valaddr;
+
+ if (len == sizeof (long))
+ return * (unsigned long *) valaddr;
+#ifdef LONG_LONG
+ if (len == sizeof (long long))
+ return * (unsigned long long *) valaddr;
+#endif
+ }
+ else if (code == TYPE_CODE_INT)
+ {
+ if (len == sizeof (char))
+ return * (char *) valaddr;
+
+ if (len == sizeof (short))
+ return * (short *) valaddr;
+
+ if (len == sizeof (int))
+ return * (int *) valaddr;
+
+ if (len == sizeof (long))
+ return * (long *) valaddr;
+
+#ifdef LONG_LONG
+ if (len == sizeof (long long))
+ return * (long long *) valaddr;
+#endif
+ }
+ else if (code == TYPE_CODE_PTR
+ || code == TYPE_CODE_REF)
+ {
+ if (len == sizeof (char *))
+ return (CORE_ADDR) * (char **) valaddr;
+ }
+ else if (code == TYPE_CODE_MEMBER)
+ error ("not implemented: member types in unpack_long");
+
+ error ("Value not integer or pointer.");
+}
+
+/* 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. */
+
+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;
+ }
+
+ if (len == sizeof (float))
+ return * (float *) valaddr;
+
+ if (len == sizeof (double))
+ {
+ /* Some machines require doubleword alignment for doubles.
+ This code works on them, and on other machines. */
+ double temp;
+ bcopy ((char *) valaddr, (char *) &temp, sizeof (double));
+ return temp;
+ }
+ }
+ else if (code == TYPE_CODE_INT && nosign)
+ {
+ if (len == sizeof (char))
+ return * (unsigned char *) valaddr;
+
+ if (len == sizeof (short))
+ return * (unsigned short *) valaddr;
+
+ if (len == sizeof (int))
+ return * (unsigned int *) valaddr;
+
+ if (len == sizeof (long))
+ return * (unsigned long *) valaddr;
+
+#ifdef LONG_LONG
+ if (len == sizeof (long long))
+ return * (unsigned long long *) valaddr;
+#endif
+ }
+ else if (code == TYPE_CODE_INT)
+ {
+ if (len == sizeof (char))
+ return * (char *) valaddr;
+
+ if (len == sizeof (short))
+ return * (short *) valaddr;
+
+ if (len == sizeof (int))
+ return * (int *) valaddr;
+
+ if (len == sizeof (long))
+ return * (long *) valaddr;
+
+#ifdef LONG_LONG
+ if (len == sizeof (long long))
+ return * (long long *) valaddr;
+#endif
+ }
+
+ error ("Value not floating number.");
+ /* NOTREACHED */
+ return (double) 0; /* To silence compiler warning. */
+}
+
+/* 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
+value_field (arg1, fieldno)
+ register value arg1;
+ register int fieldno;
+{
+ register value v;
+ register struct type *type = TYPE_FIELD_TYPE (VALUE_TYPE (arg1), fieldno);
+ register int offset;
+
+ /* Handle packed fields */
+
+ offset = TYPE_FIELD_BITPOS (VALUE_TYPE (arg1), fieldno) / 8;
+ if (TYPE_FIELD_BITSIZE (VALUE_TYPE (arg1), fieldno))
+ {
+ v = value_from_long (type,
+ unpack_field_as_long (VALUE_TYPE (arg1),
+ VALUE_CONTENTS (arg1),
+ fieldno));
+ VALUE_BITPOS (v) = TYPE_FIELD_BITPOS (VALUE_TYPE (arg1), fieldno) % 8;
+ VALUE_BITSIZE (v) = TYPE_FIELD_BITSIZE (VALUE_TYPE (arg1), fieldno);
+ }
+ else
+ {
+ v = allocate_value (type);
+ bcopy (VALUE_CONTENTS (arg1) + offset,
+ VALUE_CONTENTS (v),
+ 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;
+}
+
+value
+value_fn_field (arg1, fieldno, subfieldno)
+ register value arg1;
+ register int fieldno;
+{
+ register value v;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (VALUE_TYPE (arg1), fieldno);
+ register struct type *type = TYPE_FN_FIELD_TYPE (f, subfieldno);
+ struct symbol *sym;
+
+ sym = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, subfieldno),
+ 0, VAR_NAMESPACE, 0);
+ if (! sym) error ("Internal error: could not find physical method named %s",
+ TYPE_FN_FIELD_PHYSNAME (f, subfieldno));
+
+ v = allocate_value (type);
+ VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
+ VALUE_TYPE (v) = type;
+ return v;
+}
+
+/* Return a virtual function as a value.
+ ARG1 is the object which provides the virtual function
+ table pointer.
+ 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 basetype which first provides the virtual function table. */
+value
+value_virtual_fn_field (arg1, f, j, type)
+ value arg1;
+ struct fn_field *f;
+ int j;
+ struct type *type;
+{
+ /* 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 vfn, vtbl;
+ value vi = value_from_long (builtin_type_int,
+ (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j));
+ VALUE_TYPE (arg1) = TYPE_VPTR_BASETYPE (type);
+
+ /* 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 (type) < 0)
+ TYPE_VPTR_FIELDNO (type)
+ = fill_in_vptr_fieldno (type);
+
+ /* The virtual function table is now an array of structures
+ which have the form { int16 offset, delta; void *pfn; }. */
+ vtbl = value_ind (value_field (arg1, TYPE_VPTR_FIELDNO (type)));
+
+ /* 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. */
+ vfn = value_field (value_subscript (vtbl, vi), 2);
+
+ /* Reinstantiate the function pointer with the correct type. */
+ VALUE_TYPE (vfn) = lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j));
+ return vfn;
+}
+
+/* The value of a static class member does not depend
+ on its instance, only on its type. If FIELDNO >= 0,
+ then fieldno is a valid field number and is used directly.
+ Otherwise, FIELDNAME is the name of the field we are
+ searching for. If it is not a static field name, an
+ error is signaled. TYPE is the type in which we look for the
+ static field member. */
+value
+value_static_field (type, fieldname, fieldno)
+ register struct type *type;
+ char *fieldname;
+ register int fieldno;
+{
+ register value v;
+ struct symbol *sym;
+
+ if (fieldno < 0)
+ {
+ register struct type *t = type;
+ /* Look for static field. */
+ while (t)
+ {
+ int i;
+ for (i = TYPE_NFIELDS (t) - 1; i >= 0; i--)
+ if (! strcmp (TYPE_FIELD_NAME (t, i), fieldname))
+ {
+ if (TYPE_FIELD_STATIC (t, i))
+ {
+ fieldno = i;
+ goto found;
+ }
+ else
+ error ("field `%s' is not static");
+ }
+ t = TYPE_BASECLASSES (t) ? TYPE_BASECLASS (t, 1) : 0;
+ }
+
+ t = type;
+
+ if (destructor_name_p (fieldname, t))
+ error ("use `info method' command to print out value of destructor");
+
+ while (t)
+ {
+ int i, j;
+
+ for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; i--)
+ {
+ if (! strcmp (TYPE_FN_FIELDLIST_NAME (t, i), fieldname))
+ {
+ error ("use `info method' command to print value of method \"%s\"", fieldname);
+ }
+ }
+ t = TYPE_BASECLASSES (t) ? TYPE_BASECLASS (t, 1) : 0;
+ }
+ error("there is no field named %s", fieldname);
+ }
+
+ found:
+
+ sym = lookup_symbol (TYPE_FIELD_STATIC_PHYSNAME (type, fieldno),
+ 0, VAR_NAMESPACE, 0);
+ if (! sym) error ("Internal error: could not find physical static variable named %s", TYPE_FIELD_BITSIZE (type, fieldno));
+
+ type = TYPE_FIELD_TYPE (type, fieldno);
+ v = value_at (type, (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym));
+ return v;
+}
+
+long
+unpack_field_as_long (type, valaddr, fieldno)
+ struct type *type;
+ char *valaddr;
+ int fieldno;
+{
+ long val;
+ int bitpos = TYPE_FIELD_BITPOS (type, fieldno);
+ int bitsize = TYPE_FIELD_BITSIZE (type, fieldno);
+
+ bcopy (valaddr + bitpos / 8, &val, sizeof val);
+
+ /* Extracting bits depends on endianness of the machine. */
+#ifdef BITS_BIG_ENDIAN
+ val = val >> (sizeof val * 8 - bitpos % 8 - bitsize);
+#else
+ val = val >> (bitpos % 8);
+#endif
+
+ val &= (1 << bitsize) - 1;
+ return val;
+}
+
+void
+modify_field (addr, fieldval, bitpos, bitsize)
+ char *addr;
+ int fieldval;
+ int bitpos, bitsize;
+{
+ long oword;
+
+ /* Reject values too big to fit in the field in question.
+ Otherwise adjoining fields may be corrupted. */
+ if (fieldval & ~((1<<bitsize)-1))
+ error ("Value %d does not fit in %d bits.", fieldval, bitsize);
+
+ bcopy (addr, &oword, sizeof oword);
+
+ /* Shifting for bit field depends on endianness of the machine. */
+#ifdef BITS_BIG_ENDIAN
+ bitpos = sizeof (oword) * 8 - bitpos - bitsize;
+#endif
+
+ oword &= ~(((1 << bitsize) - 1) << bitpos);
+ oword |= fieldval << bitpos;
+ bcopy (&oword, addr, sizeof oword);
+}
+
+/* Convert C numbers into newly allocated values */
+
+value
+value_from_long (type, num)
+ struct type *type;
+ register LONGEST num;
+{
+ register value val = allocate_value (type);
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+
+ if (code == TYPE_CODE_INT || code == TYPE_CODE_ENUM)
+ {
+ if (len == sizeof (char))
+ * (char *) VALUE_CONTENTS (val) = num;
+ else if (len == sizeof (short))
+ * (short *) VALUE_CONTENTS (val) = num;
+ else if (len == sizeof (int))
+ * (int *) VALUE_CONTENTS (val) = num;
+ else if (len == sizeof (long))
+ * (long *) VALUE_CONTENTS (val) = num;
+#ifdef LONG_LONG
+ else if (len == sizeof (long long))
+ * (long long *) VALUE_CONTENTS (val) = num;
+#endif
+ else
+ error ("Integer type encountered with unexpected data length.");
+ }
+ else
+ error ("Unexpected type encountered for integer constant.");
+
+ return val;
+}
+
+value
+value_from_double (type, num)
+ struct type *type;
+ double num;
+{
+ register value val = allocate_value (type);
+ register enum type_code code = TYPE_CODE (type);
+ register int len = TYPE_LENGTH (type);
+
+ if (code == TYPE_CODE_FLT)
+ {
+ if (len == sizeof (float))
+ * (float *) VALUE_CONTENTS (val) = num;
+ else if (len == sizeof (double))
+ * (double *) VALUE_CONTENTS (val) = num;
+ else
+ error ("Floating type encountered with unexpected data length.");
+ }
+ 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
+value_being_returned (valtype, retbuf, struct_return)
+ register struct type *valtype;
+ char retbuf[REGISTER_BYTES];
+ int struct_return;
+{
+ register value val;
+
+ if (struct_return)
+ return value_at (valtype, EXTRACT_STRUCT_VALUE_ADDRESS (retbuf));
+
+ val = allocate_value (valtype);
+ EXTRACT_RETURN_VALUE (valtype, retbuf, VALUE_CONTENTS (val));
+
+ return val;
+}
+
+/* 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 */
+
+struct block *block_for_pc ();
+
+int
+using_struct_return (function, funcaddr, value_type)
+ value function;
+ CORE_ADDR funcaddr;
+ struct type *value_type;
+{
+ register enum type_code code = TYPE_CODE (value_type);
+
+ if (code == TYPE_CODE_STRUCT ||
+ code == TYPE_CODE_UNION ||
+ code == TYPE_CODE_ARRAY)
+ {
+ struct block *b = block_for_pc (funcaddr);
+
+ if (!(BLOCK_GCC_COMPILED (b) && TYPE_LENGTH (value_type) < 8))
+ return 1;
+ }
+
+ 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 val;
+{
+ register enum type_code code = TYPE_CODE (VALUE_TYPE (val));
+ char regbuf[REGISTER_BYTES];
+ double dbuf;
+ LONGEST lbuf;
+
+ if (code == TYPE_CODE_STRUCT
+ || code == TYPE_CODE_UNION)
+ error ("Specifying a struct or union return value is not supported.");
+
+ if (code == TYPE_CODE_FLT)
+ {
+ dbuf = value_as_double (val);
+
+ STORE_RETURN_VALUE (VALUE_TYPE (val), &dbuf);
+ }
+ else
+ {
+ lbuf = value_as_long (val);
+ STORE_RETURN_VALUE (VALUE_TYPE (val), &lbuf);
+ }
+}
+
+void
+_initialize_values ()
+{
+ add_info ("convenience", convenience_info,
+ "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 GDB:\n\
+\"$_\"holds the last address examined with \"x\" or \"info lines\",\n\
+\"$__\" holds the contents of the last address examined with \"x\".");
+
+ add_info ("values", value_history_info,
+ "Elements of value history (around item number IDX, or last ten).");
+ add_info_alias ("history", value_history_info, 0);
+}
diff --git a/gnu/usr.bin/gdb/version.c b/gnu/usr.bin/gdb/version.c
new file mode 100644
index 0000000..2f3dd85
--- /dev/null
+++ b/gnu/usr.bin/gdb/version.c
@@ -0,0 +1,20 @@
+/* Define the current version number of GDB.
+ Copyright (C) 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. */
+
+char *version = "3.5";
diff --git a/gnu/usr.bin/gdb/wait.h b/gnu/usr.bin/gdb/wait.h
new file mode 100644
index 0000000..c431cb6
--- /dev/null
+++ b/gnu/usr.bin/gdb/wait.h
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson and Steven McCanne of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wait.h 6.3 (Berkeley) 5/8/91
+ */
+
+/* Define how to access the structure that the wait system call stores.
+ On many systems, there is a structure defined for this.
+ But on vanilla-ish USG systems there is not. */
+
+#ifndef HAVE_WAIT_STRUCT
+
+#define WAITTYPE int
+#define WIFSTOPPED(w) (((w)&0377) == 0177)
+#define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
+#define WIFEXITED(w) (((w)&0377) == 0)
+#define WEXITSTATUS(w) ((w) >> 8)
+#define WSTOPSIG(w) ((w) >> 8)
+#define WCOREDUMP(w) (((w)&0200) != 0)
+#define WTERMSIG(w) ((w) & 0177)
+#define WSETEXIT(w, status) ((w) = (status))
+#define WSETSTOP(w,sig) ((w) = (0177 | ((sig) << 8)))
+
+#else
+
+#include <sys/wait.h>
+
+#define WAITTYPE union wait
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(w) (w).w_retcode
+#endif
+#ifndef WSTOPSIG
+#define WSTOPSIG(w) (w).w_stopsig
+#endif
+#ifndef WCOREDUMP
+#define WCOREDUMP(w) (w).w_coredump
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(w) (w).w_termsig
+#endif
+#ifndef WSETEXIT
+#define WSETEXIT(w, status) ((w).w_status = (status))
+#endif
+#ifndef WSETSTOP
+#define WSETSTOP(w,sig) \
+ ((w).w_stopsig = (sig), (w).w_coredump = 0, (w).w_termsig = 0177)
+#endif
+
+#endif
diff --git a/gnu/usr.bin/gdb/xgdb/Makefile b/gnu/usr.bin/gdb/xgdb/Makefile
new file mode 100644
index 0000000..72c5359
--- /dev/null
+++ b/gnu/usr.bin/gdb/xgdb/Makefile
@@ -0,0 +1,33 @@
+# %W% (Berkeley) %G%
+
+.include "../config/Makefile.$(MACHINE)"
+
+PROG= xgdb
+SRCS= xgdb.c xgdbinit.c
+GDBOBJS+= $(CONFIGSRCS:R:S/$/.o/g) \
+ blockframe.o breakpoint.o command.o copying.o core.o \
+ cplus-dem.o dbxread.o environ.o eval.o expprint.o \
+ expread.o findvar.o infcmd.o inflow.o infrun.o \
+ main.o obstack.o printcmd.o regex.o remote.o \
+ remote-sl.o source.o stack.o symmisc.o symtab.o \
+ utils.o valarith.o valops.o valprint.o values.o \
+ version.o \
+ funmap.o history.o keymaps.o readline.o
+CFLAGS+= -I.. -I$(.CURDIR)/.. -I$(.CURDIR)/../config \
+ -DHAVE_VPRINTF -DVI_MODE -DKERNELDEBUG
+LDFLAGS+= -L/usr/lib/X11
+LDADD+= $(GDBOBJS:S/^/..\//g) -lXaw -lXmu -lXt -lXext -lX11 -ltermcap
+NOMAN= noman
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
+
+#
+# Generate the constructor
+#
+xgdbinit.c: ../init.c xgdb.c
+ -(sed -e '/^}$$/d' ../init.c; \
+ egrep -h '^_initialize_[^ ]* *\(\)' $(.CURDIR)/xgdb.c; \
+ echo ';}') > xgdbinit.c
+
+CLEANFILES+= xgdbinit.c
diff --git a/gnu/usr.bin/gdb/xgdb/xgdb.c b/gnu/usr.bin/gdb/xgdb/xgdb.c
new file mode 100644
index 0000000..a2bd4f6
--- /dev/null
+++ b/gnu/usr.bin/gdb/xgdb/xgdb.c
@@ -0,0 +1,700 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
+ *
+ * static char rcsid[] = "$Header: /home/cvs/386BSD/src/usr.bin/gdb/xgdb/xgdb.c,v 1.1.1.1 1993/06/12 14:52:36 rgrimes Exp $";
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)xgdb.c 6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/*
+ * Interface from GDB to X windows. Copyright (C) 1987 Free Software
+ * Foundation, Inc.
+ *
+ * GDB 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 GDB
+ * General Public License for full details.
+ *
+ * Everyone is granted permission to copy, modify and redistribute GDB, but only
+ * under the conditions described in the GDB General Public License. A copy
+ * of this license is supposed to have been given to you along with GDB 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.
+ *
+ * In other words, go ahead and share GDB, but don't try to stop anyone else
+ * from sharing it farther. Help stamp out software hoarding!
+ */
+
+/*
+ * Original version was contributed by Derek Beatty, 30 June 87.
+ * This version is essentially a re-write of the original by Van
+ * Jacobson (van@helios.ee.lbl.gov), Nov, 90.
+ */
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+
+extern int stop_breakpoint;
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xaw/AsciiSink.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/Paned.h>
+#include <X11/Xaw/Text.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+
+extern int errno;
+extern char *getenv();
+extern char *malloc();
+extern void bcopy();
+extern int select();
+
+extern int get_filename_and_charpos();
+extern int source_line_charpos();
+extern int source_charpos_line();
+extern void execute_command();
+extern void error_no_arg();
+extern void add_com();
+
+/* The X display where the window appears. */
+
+static char *displayname;
+static Display *display;
+
+static XtAppContext app_context;
+
+/* Windows manipulated by this package. */
+
+static Widget main_widget;
+static Widget containing_widget;
+static Widget source_name_widget;
+static Widget source_text_widget;
+static Widget button_box_widget;
+
+/* Source text display. */
+
+static struct frame_info *last_fi;
+static CORE_ADDR last_pc;
+static struct symtab *last_cur_symtab;
+static int last_cur_line;
+
+static int source_window_line;
+static char *source_window_file;
+static struct symtab *source_window_symtab;
+
+static char version_label[64];
+extern char *version;
+
+/* Forward declarations */
+
+static Widget create_text_widget();
+
+static int
+safe_strcmp(a, b)
+ register char *a, *b;
+{
+ register int i;
+
+ if (a == b)
+ return (0);
+ if (!a && b)
+ return (1);
+ if (a && !b)
+ return (-1);
+ return (strcmp(a, b));
+}
+
+
+/* Display an appropriate piece of source code in the source window. */
+
+void
+xgdb_display_source()
+{
+ char *filename = NULL;
+ struct symtab_and_line get_selected_frame_sal();
+ struct symtab_and_line sal;
+ struct frame_info *fi;
+
+ /* Do nothing if called before we are initialized */
+
+ if (!containing_widget)
+ return;
+
+ /*
+ * Figure out what to display (the appropriate hooks to tell
+ * us don't exist so we guess): If there's a current frame
+ * and it or its pc changed from the last time we were here,
+ * display appropriate source line. Otherwise if the current
+ * source symtab or line is different, display that line.
+ * Otherwise nothing changed so leave the display alone.
+ */
+ fi = get_frame_info(selected_frame);
+ if (fi && (fi != last_fi || fi->pc != last_pc)) {
+ last_fi = fi;
+ last_pc = fi->pc;
+ sal = find_pc_line(fi->pc, fi->next_frame);
+ if (sal.symtab == NULL) { /* XXX */
+ sal.symtab = current_source_symtab;
+ sal.line = current_source_line;
+ }
+ current_source_symtab = sal.symtab;
+ current_source_line = sal.line;
+ } else if (current_source_symtab != last_cur_symtab ||
+ current_source_line != last_cur_line) {
+ sal.symtab = last_cur_symtab = current_source_symtab;
+ sal.line = last_cur_line = current_source_line;
+ } else
+ return;
+ /*
+ * Do a path search and get the exact filename of this source file.
+ * Also scan it and find its source lines if not already done.
+ */
+ if (sal.symtab && filename == NULL) {
+ if (get_filename_and_charpos(sal.symtab, sal.line, &filename))
+ /* line numbers may have changed - force highlight */
+ source_window_line = -1;
+ }
+
+ /*
+ * If the source window is wrong, destroy it and make a new one.
+ */
+ if (safe_strcmp(filename, source_window_file)) {
+ Arg args[1];
+ Widget src = XawTextGetSource(source_text_widget);
+
+ if (filename) {
+ XtSetArg(args[0], XtNstring, filename);
+ XtSetValues(src, args, XtNumber(args));
+ args[0].name = XtNlabel;
+ XtSetValues(source_name_widget, args, XtNumber(args));
+ } else {
+ XtSetArg(args[0], XtNstring, "/dev/null");
+ XtSetValues(src, args, XtNumber(args));
+ XtSetArg(args[0], XtNlabel, "");
+ XtSetValues(source_name_widget, args, XtNumber(args));
+ }
+ if (source_window_file)
+ free(source_window_file);
+ source_window_file = filename;
+ source_window_line = sal.line + 1; /* force highlight */
+ }
+ if (sal.symtab && source_window_line != sal.line) {
+ /*
+ * Update display and cursor positions as necessary.
+ * Cursor should be placed on line sal.line.
+ */
+ XawTextPosition l, r;
+
+ source_window_symtab = sal.symtab;
+ source_window_line = sal.line;
+ l = source_line_charpos(source_window_symtab, sal.line);
+ r = source_line_charpos(source_window_symtab, sal.line + 1);
+ if (r < l)
+ r = l + 1;
+ XawTextSetSelection(source_text_widget, l, r);
+ XawTextScrollToLine(source_text_widget, l, 10, 3);
+ XawTextSetInsertionPoint(source_text_widget, l);
+ }
+}
+
+
+/*
+ * Handlers for buttons.
+ */
+
+static int
+current_lineno()
+{
+ XawTextPosition start, finish;
+
+ XawTextGetSelectionPos(source_text_widget, &start, &finish);
+ if (start >= finish)
+ start = XawTextGetInsertionPoint(source_text_widget);
+
+ return (source_charpos_line(source_window_symtab, start));
+}
+
+static char *
+append_selection(cp)
+ char *cp;
+{
+ int len;
+ XawTextPosition l, r;
+
+ XawTextGetSelectionPos(source_text_widget, &l, &r);
+ if ((len = r - l) > 0) {
+ Widget src = XawTextGetSource(source_text_widget);
+
+ while (len > 0) {
+ XawTextBlock tb;
+
+ XawTextSourceRead(src, l, &tb, len);
+ bcopy(tb.ptr, cp, tb.length);
+ cp += tb.length;
+ len -= tb.length;
+ }
+ if (cp[-1] == 0)
+ --cp;
+ }
+ return (cp);
+}
+
+static char *
+append_selection_word(cp)
+ register char *cp;
+{
+ register int len;
+ XawTextPosition l, r;
+ XawTextBlock tb;
+ register char c;
+ register Widget src = XawTextGetSource(source_text_widget);
+
+ XawTextGetSelectionPos(source_text_widget, &l, &r);
+ if ((len = r - l) <= 0) {
+ l = XawTextGetInsertionPoint(source_text_widget);
+ len = 128; /* XXX */
+
+ /* might have clicked in middle of word -- back up to start */
+ for ( ; l > 0; --l) {
+ XawTextSourceRead(src, l - 1, &tb, 1);
+ c = tb.ptr[0];
+ if (! isalnum(c) && c != '_' && c != '$')
+ break;
+ }
+ }
+ while (len > 0) {
+ char *sp;
+ int i;
+
+ XawTextSourceRead(src, l, &tb, len);
+ for (sp = tb.ptr, i = tb.length; --i >= 0; ) {
+ c = *sp++;
+ if (!isalnum(c) && c != '_' && c != '$')
+ return (cp);
+ *cp++ = c;
+ }
+ len -= tb.length;
+ }
+ return (cp);
+}
+
+static char *
+append_selection_expr(cp)
+ char *cp;
+{
+ int len;
+ XawTextPosition l, r;
+ Widget src = XawTextGetSource(source_text_widget);
+ XawTextBlock tb;
+ char *sp;
+ char c;
+
+ XawTextGetSelectionPos(source_text_widget, &l, &r);
+ if (r > l)
+ return (append_selection(cp));
+
+ l = XawTextGetInsertionPoint(source_text_widget);
+
+ /* might have clicked in middle of word -- back up to start */
+ for ( ; l > 0; --l) {
+ XawTextSourceRead(src, l - 1, &tb, 1);
+ c = tb.ptr[0];
+ if (! isalnum(c) && c != '_' && c != '$')
+ break;
+ }
+
+ len = 128; /* XXX */
+ while (len > 0) {
+ int i;
+ char pstack[64];
+ int pcnt = 0;
+
+ XawTextSourceRead(src, l, &tb, len);
+ for (sp = tb.ptr, i = tb.length; --i >= 0; ) {
+ switch (c = *sp++) {
+ case '\n':
+ case ';':
+ return (cp);
+ case '=':
+ if (cp[-1] != '=')
+ return (cp - 1);
+ if (len == 128)
+ return (cp);
+ break;
+ case ',':
+ if (pcnt <= 0)
+ return (cp);
+ break;
+ case '(':
+ pstack[pcnt] = ')';
+ if (++pcnt >= sizeof(pstack))
+ return (cp);
+ break;
+ case '[':
+ pstack[pcnt] = ']';
+ if (++pcnt >= sizeof(pstack))
+ return (cp);
+ break;
+ case ')':
+ case ']':
+ if (--pcnt < 0 || pstack[pcnt] != c)
+ return (cp);
+ break;
+ }
+ *cp++ = c;
+ }
+ len -= tb.length;
+ }
+ return (cp);
+}
+
+static int input_avail; /* XXX kluge: do_command sets this when command
+ * data from button is avaialble to force top level
+ * to break out of its loop. */
+/*
+ * Handle a button by running the command COMMAND.
+ */
+static void
+do_command(w, command, call_data)
+ Widget w;
+ register char *command;
+ caddr_t call_data;
+{
+ char cmd_line[256];
+ char buf[256];
+ register char *out = cmd_line;
+ char *cp;
+ register char c;
+ extern char *finish_command_input();
+
+ while (c = *command++) {
+ if (c == '%') {
+ switch (*command++) {
+ case 's': /* current selection */
+ out = append_selection(out);
+ break;
+ case 'S': /* 1st selected "word" at curor */
+ out = append_selection_word(out);
+ break;
+ case 'e': /* echo cmd before executing */
+ break;
+ case 'E': /* 1st selected expression at curor */
+ out = append_selection_expr(out);
+ break;
+
+ case 'l': /* current line number */
+ (void) sprintf(buf, "%d", current_lineno());
+ for (cp = buf; c = *cp++; *out++ = c)
+ ;
+ break;
+ case 'L': /* line we're stopped at */
+ (void) sprintf(buf, "%d", source_window_line);
+ for (cp = buf; c = *cp++; *out++ = c)
+ ;
+ break;
+ case 'f': /* current file name */
+ for (cp = source_window_symtab->filename;
+ c = *cp++; *out++ = c)
+ ;
+ break;
+ case 'b': /* break # we're stopped at */
+ if (stop_breakpoint <= 0)
+ /* if no breakpoint, don't do cmd */
+ return;
+
+ (void) sprintf(buf, "%d", stop_breakpoint);
+ for (cp = buf; c = *cp++; *out++ = c)
+ ;
+ break;
+ }
+ } else
+ *out++ = c;
+ }
+ *out = 0;
+ reinitialize_more_filter();
+ /* have to exit via readline or tty modes stay messed up */
+ for (cp = cmd_line; c = *cp++; )
+ rl_stuff_char(c);
+ rl_stuff_char('\n');
+ input_avail = 1;
+}
+
+/*
+ * Define and display all the buttons.
+ */
+static void
+addbutton(parent, name, function, closure)
+ Widget parent;
+ char *name;
+ void (*function) ();
+ caddr_t closure;
+{
+ static XtCallbackRec Callback[] = {
+ {NULL, (caddr_t) NULL},
+ {NULL, (caddr_t) NULL},
+ };
+ static Arg commandArgs[] = {
+ {XtNlabel, (XtArgVal) NULL},
+ {XtNcallback, (XtArgVal) Callback},
+ };
+ Widget w;
+ char wname[128];
+ register char *cp;
+
+ strcpy(wname, name);
+ while ((cp = index(wname, '*')) || (cp = index(wname, '.')))
+ *cp -= 0x10;
+
+ if (w = XtNameToWidget(parent, wname))
+ XtDestroyWidget(w);
+
+ Callback[0].callback = (XtCallbackProc) function;
+ Callback[0].closure = (caddr_t) closure;
+ commandArgs[0].value = (XtArgVal) name;
+ XtCreateManagedWidget(wname, commandWidgetClass, parent,
+ commandArgs, XtNumber(commandArgs));
+}
+
+/*
+ * Create the button windows and store them in `buttons'.
+ */
+static void
+create_buttons(parent)
+ Widget parent;
+{
+ addbutton(parent, "quit", do_command, "quit");
+}
+
+static void
+button_command(arg)
+ char *arg;
+{
+ char *label;
+ unsigned int len;
+
+ if (! arg)
+ error_no_arg("button label and command");
+
+ for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len)
+ ;
+ if (len == 0)
+ error_no_arg("button label and command");
+ arg[len] = 0;
+
+ /* make a copy of button label & command for toolkit to use */
+ label = malloc(len + 1);
+ strcpy(label, arg);
+
+ /* find the end of the label */
+ if (*label == '"') {
+ if ((arg = index(++label, '"')) == 0) {
+ printf("button label missing closing quote\n");
+ return;
+ }
+ *arg++ = 0;
+ } else if (arg = index(label, ' '))
+ *arg++ = 0;
+ else
+ arg = label;
+
+ while (*arg && isspace(*arg))
+ ++arg;
+
+ addbutton(button_box_widget, label, do_command, arg);
+}
+
+static void
+button_delete_command(arg)
+ char *arg;
+{
+ unsigned int len;
+ Widget w;
+ register char *cp;
+
+ if (! arg)
+ error_no_arg("button name");
+
+ for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len)
+ ;
+ if (len == 0)
+ error_no_arg("button name");
+ arg[len] = 0;
+
+ /* find the end of the label */
+ if (*arg == '"') {
+ if ((cp = index(++arg, '"')) == 0) {
+ printf("button label missing closing quote\n");
+ return;
+ }
+ *cp++ = 0;
+ }
+ while ((cp = index(arg, '*')) || (cp = index(arg, '.')))
+ *cp -= 0x10;
+
+ if (w = XtNameToWidget(button_box_widget, arg))
+ XtDestroyWidget(w);
+}
+
+/*
+ * Create a "label window" that just displays the string LABEL.
+ */
+static Widget
+create_label(name, label)
+ char *name, *label;
+{
+ Arg args[1];
+ Widget w;
+
+ XtSetArg(args[0], XtNlabel, label);
+ w = XtCreateManagedWidget(name, labelWidgetClass, containing_widget,
+ args, XtNumber(args));
+ return (w);
+}
+
+/*
+ * Create a subwindow of PARENT that displays and scrolls the contents of
+ * file FILENAME.
+ */
+static Widget
+create_text_widget(parent, filename)
+ Widget parent;
+ char *filename;
+{
+ static Arg arg[] = {
+ {XtNstring, NULL},
+ {XtNtype, XawAsciiFile},
+ {XtNcursor, None},
+ };
+ Widget text_widget;
+
+ arg[0].value = (XtArgVal)filename;
+ text_widget = XtCreateManagedWidget("src", asciiTextWidgetClass,
+ parent, arg, XtNumber(arg));
+ return (text_widget);
+}
+
+/*
+ * Entry point to create the widgets representing our display.
+ */
+void
+xgdb_create_window()
+{
+ /* initialize toolkit, setup defaults */
+#ifdef notyet
+ main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0,
+ argcptr, argv, NULL, NULL, 0);
+#else
+ char *dummy_argv[] = { "xgdb", 0 };
+ int dummy_argc = 1;
+ main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0,
+ &dummy_argc, dummy_argv, NULL, NULL, 0);
+#endif
+ display = XtDisplay(main_widget);
+ containing_widget = XtCreateManagedWidget("frame", panedWidgetClass,
+ main_widget, NULL, 0);
+
+ sprintf(version_label, "XGDB %s", version);
+ button_box_widget = XtCreateManagedWidget("buttons", boxWidgetClass,
+ containing_widget, NULL, 0);
+ create_buttons(button_box_widget);
+ source_name_widget = create_label("srcLabel", "No source file yet.");
+ source_text_widget = create_text_widget(containing_widget, "/dev/null");
+
+ XtRealizeWidget(main_widget);
+ XFlush(display);
+}
+
+/*
+ * If we use an X window, the readline input loop is told to call
+ * this function before reading a character from stdin.
+ */
+/*ARGSUSED*/
+static void
+xgdb_window_hook()
+{
+ register int inmask = 1 << fileno(stdin);
+ register int xmask = 1 << ConnectionNumber(display);
+ register int nfds, pend;
+ int input_rfds;
+ XEvent ev;
+
+ /*
+ * Display our current idea of the `interesting' source file then
+ * loop, dispatching window events until data is available on
+ * stdin. Then return so the input data can be processed.
+ */
+ input_avail = 0;
+ xgdb_display_source();
+
+ input_rfds = 0;
+ while (input_avail == 0 && (input_rfds & inmask) == 0) {
+ pend = XPending(display);
+ if (!pend) {
+ input_rfds = inmask | xmask;
+ nfds = select(32, &input_rfds, 0, 0,
+ (struct timeval *)0);
+ if (nfds == -1 && errno == EINTR)
+ continue;
+ }
+ if (pend || (input_rfds & xmask)) {
+ XNextEvent(display, &ev);
+ XtDispatchEvent(&ev);
+ }
+ }
+}
+
+void
+_initialize_xgdb()
+{
+ extern void (*window_hook) ();
+ extern int inhibit_windows;
+ extern struct cmd_list_element *deletelist;
+
+ if (inhibit_windows)
+ return;
+
+ if (! displayname) {
+ displayname = getenv("DISPLAY");
+ if (! displayname) {
+ fprintf(stderr, "xgdb: no display name\n");
+ inhibit_windows = 1;
+ return;
+ }
+ }
+ xgdb_create_window();
+ window_hook = xgdb_window_hook;
+ add_com("button", class_support, button_command,
+"Add command button to xgdb window. First argument is button\n\
+label, second is command associated with button. Command can\n\
+include printf-like escapes:\n\
+ %s for current selection,\n\
+ %S for first 'word' of current selection,\n\
+ %e for current selection or expression at insertion pt,\n\
+ %E for current selection or expression at insertion pt,\n\
+ %l for current line number,\n\
+ %L for line program stopped at,\n\
+ %f for current file name,\n\
+ %b for current breakpoint number.");
+ add_cmd("button", class_support, button_delete_command,
+"Delete a button from the xgdb window.\n\
+Argument is name of button to be deleted.",
+ &deletelist);
+}
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..c8d4915
--- /dev/null
+++ b/gnu/usr.bin/grep/Makefile
@@ -0,0 +1,14 @@
+PROG= grep
+SRCS= dfa.c grep.c getopt.c kwset.c obstack.c regex.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
+
+LINKS+= ${BINDIR}/grep ${BINDIR}/egrep \
+ ${BINDIR}/grep ${BINDIR}/fgrep
+MLINKS= grep.1 egrep.1 grep.1 fgrep.1
+
+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..fc649af
--- /dev/null
+++ b/gnu/usr.bin/grep/dfa.c
@@ -0,0 +1,2525 @@
+/* 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
+
+#ifdef isascii
+#define ISALPHA(C) (isascii(C) && isalpha(C))
+#define ISUPPER(C) (isascii(C) && isupper(C))
+#define ISLOWER(C) (isascii(C) && islower(C))
+#define ISDIGIT(C) (isascii(C) && isdigit(C))
+#define ISXDIGIT(C) (isascii(C) && isxdigit(C))
+#define ISSPACE(C) (isascii(C) && isspace(C))
+#define ISPUNCT(C) (isascii(C) && ispunct(C))
+#define ISALNUM(C) (isascii(C) && isalnum(C))
+#define ISPRINT(C) (isascii(C) && isprint(C))
+#define ISGRAPH(C) (isascii(C) && isgraph(C))
+#define ISCNTRL(C) (isascii(C) && iscntrl(C))
+#else
+#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)
+#endif
+
+#include "dfa.h"
+#include "regex.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..27c6b0e
--- /dev/null
+++ b/gnu/usr.bin/grep/grep.1
@@ -0,0 +1,375 @@
+.TH GREP 1 "1992 September 10" "GNU Project"
+.SH NAME
+grep, egrep, fgrep \- print lines matching a pattern
+.SH SYNOPOSIS
+.B grep
+[
+.BR \- [[ AB "] ]\c"
+.I "num"
+]
+[
+.BR \- [ CEFGVBchilnsvwx ]
+]
+[
+.B \-e
+]
+.I pattern
+|
+.BI \-f file
+] [
+.I 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 \-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.
+.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..07872a1
--- /dev/null
+++ b/gnu/usr.bin/grep/grep.c
@@ -0,0 +1,826 @@
+/* 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>
+
+#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
+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
+
+/* 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;
+}
+
+/* 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;
+
+ 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";
+
+#define USAGE \
+ "usage: %s [-[[AB] ]<num>] [-[CEFGVchilnqsvwx]] [-[ef]] <expr> [<files...>]\n"
+
+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;
+
+ 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;
+
+ while ((opt = getopt(argc, argv, "0123456789A:B:CEFGVX:bce:f:hiLlnqsvwxy"))
+ != 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;
+ 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);
+
+ if (argc - optind > 1 && !no_filenames)
+ out_file = 1;
+
+ status = 1;
+
+ 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;
+ }
+ 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..9b09071
--- /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..8a18e45
--- /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/regex.c b/gnu/usr.bin/grep/regex.c
new file mode 100644
index 0000000..e8b5882
--- /dev/null
+++ b/gnu/usr.bin/grep/regex.c
@@ -0,0 +1,4987 @@
+/* Extended regular expression matching and search library,
+ version 0.12.
+ (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>
+
+/* Jim Meyering writes:
+
+ "... Some ctype macros are valid only for character codes that
+ isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+ using /bin/cc or gcc but without giving an ansi option). So, all
+ ctype uses should be through macros like ISPRINT... If
+ STDC_HEADERS is defined, then autoconf has verified that the ctype
+ macros don't need to be guarded with references to isascii. ...
+ Defining isascii to 1 should let any compiler worth its salt
+ eliminate the && through constant folding." */
+#if ! defined (isascii) || defined (STDC_HEADERS)
+#undef 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)
+ {
+ printf ("%d:\t", p - start);
+
+ 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, last = -100;
+ register int in_range = 0;
+
+ printf ("/charset [%s",
+ (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
+
+ assert (p + *p < pend);
+
+ for (c = 0; c < 256; c++)
+ if (c / 8 < *p
+ && (p[1 + (c/8)] & (1 << (c % 8))))
+ {
+ /* Are we starting a range? */
+ if (last + 1 == c && ! in_range)
+ {
+ putchar ('-');
+ in_range = 1;
+ }
+ /* Have we broken a range? */
+ else if (last + 1 != c && in_range)
+ {
+ printchar (last);
+ in_range = 0;
+ }
+
+ if (! in_range)
+ printchar (c);
+
+ last = c;
+ }
+
+ if (in_range)
+ printchar (last);
+
+ putchar (']');
+
+ 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 to %d", p + mcnt - start);
+ break;
+
+ case on_failure_keep_string_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/on_failure_keep_string_jump to %d", p + mcnt - start);
+ break;
+
+ case dummy_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/dummy_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case push_dummy_failure:
+ printf ("/push_dummy_failure");
+ break;
+
+ case maybe_pop_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/maybe_pop_jump to %d", p + mcnt - start);
+ break;
+
+ case pop_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/pop_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case jump_past_alt:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump_past_alt to %d", p + mcnt - start);
+ break;
+
+ case jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump to %d", p + mcnt - start);
+ break;
+
+ case succeed_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/succeed_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case jump_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/jump_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case set_number_at:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/set_number_at location %d to %d", p + mcnt - start, 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));
+ }
+
+ putchar ('\n');
+ }
+
+ printf ("%d:\tend of pattern.\n", p - start);
+}
+
+
+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 ('.')
+ && zero_times_ok
+ && 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;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+ 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;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+
+ /* 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: \n");
+ 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
+ {
+ /* These braces fend off a "empty body in an else-statement"
+ warning under GCC when assert expands to nothing. */
+ 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;
+ preg->used = 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 = re_error_msg[errcode];
+
+ /* POSIX doesn't require that we do anything in this case, but why
+ not be nice. */
+ if (! msg)
+ msg = "Success";
+
+ 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/grep/regex.h b/gnu/usr.bin/grep/regex.h
new file mode 100644
index 0000000..408dd21
--- /dev/null
+++ b/gnu/usr.bin/grep/regex.h
@@ -0,0 +1,490 @@
+/* Definitions for data structures and routines for the regular
+ expression library, version 0.12.
+
+ Copyright (C) 1985, 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. */
+
+#ifndef __REGEXP_LIBRARY_H__
+#define __REGEXP_LIBRARY_H__
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+ <regex.h>. */
+
+#ifdef VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+ should be there. */
+#include <stddef.h>
+#endif
+
+
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* 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 (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions, of course).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+
+ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+ POSIX draft 11.2 says that * etc. in leading positions is undefined.
+ We already implemented a previous draft which made those constructs
+ invalid, though, so we haven't changed the code back. */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+ than the starting range point, as in [z-a], is invalid.
+ If not set, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t re_syntax_options;
+
+/* Define combinations of the above bits for the standard possibilities.
+ (The [[[ comments delimit what gets put into the Texinfo file, so
+ don't delete them!) */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
+ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
+ | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP \
+ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _RE_SYNTAX_POSIX_COMMON \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+ replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow. Some systems
+ (erroneously) define this in other header files, but we want our
+ value, so remove any previous define. */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+#define RE_DUP_MAX ((1 << 15) - 1)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp'). */
+
+/* If this bit is set, then use extended regular expression syntax.
+ If not set, then use basic regular expression syntax. */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+ characters in the string.
+ If not set, then anchors do match at newlines. */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+ If not set, then returns differ between not matching and errors. */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec). */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+ the beginning of the string (presumably because it's not the
+ beginning of a line).
+ If not set, then the beginning-of-line operator does match the
+ beginning of the string. */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line. */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Not implemented. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `no_sub' can be set. After the pattern has been
+ compiled, the `re_nsub' field is available. All other fields are
+ private to the regex routines. */
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+ /* Space that holds the compiled pattern. It is declared as
+ `unsigned char *' because its elements are
+ sometimes used as array indexes. */
+ unsigned char *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t syntax;
+
+ /* Pointer to a fastmap, if any, otherwise zero. re_search uses
+ the fastmap, if there is one, to skip over impossible
+ starting points for matches. */
+ char *fastmap;
+
+ /* Either a translate table to apply to all characters before
+ comparing them, or zero for no translation. The translation
+ is applied to a pattern when it is compiled and to a string
+ when it is matched. */
+ char *translate;
+
+ /* Number of subexpressions found by the compiler. */
+ size_t re_nsub;
+
+ /* Zero if this pattern cannot match the empty string, one else.
+ Well, in truth it's used only in `re_search_2', to see
+ whether or not we should use the fastmap, so we don't set
+ this absolutely perfectly; see `re_compile_fastmap' (the
+ `duplicate' case). */
+ unsigned can_be_null : 1;
+
+ /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+ for `max (RE_NREGS, re_nsub + 1)' groups.
+ If REGS_REALLOCATE, reallocate space if necessary.
+ If REGS_FIXED, use what's there. */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+ unsigned regs_allocated : 2;
+
+ /* Set to zero when `regex_compile' compiles a pattern; set to one
+ by `re_compile_fastmap' if it updates the fastmap. */
+ unsigned fastmap_accurate : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the
+ beginning of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+
+/* search.c (search_buffer) in Emacs needs this one opcode value. It is
+ defined both in `regex.c' and here. */
+#define RE_EXACTN_VALUE 1
+
+/* Type for byte offsets within the string. POSIX mandates this. */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+ `re_match_2' returns information about at least this many registers
+ the first time a `regs' structure is passed. */
+#ifndef RE_NREGS
+#define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers. Aside from the different names than
+ `re_registers', POSIX uses an array of structures, instead of a
+ structure of arrays. */
+typedef struct
+{
+ regoff_t rm_so; /* Byte offset from string's start to substring's start. */
+ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
+} regmatch_t;
+
+/* Declarations for routines. */
+
+/* To avoid duplicating every routine declaration -- once with a
+ prototype (if we are ANSI), and once without (if we aren't) -- we
+ use the following macro to declare argument types. This
+ unfortunately clutters up the declarations a bit, but I think it's
+ worth it. */
+
+#if __STDC__
+
+#define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+#define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+ You can also simply assign to the `re_syntax_options' variable. */
+extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+/* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `re_syntax_options', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+extern const char *re_compile_pattern
+ _RE_ARGS ((const char *pattern, int length,
+ struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+ compiled into BUFFER. Start searching at position START, for RANGE
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->no_sub are nonzero). */
+extern int re_search
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+extern int re_search_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int re_match
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int re_match_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using BUFFER and REGS will use this memory
+ for recording register information. STARTS and ENDS must be
+ allocated with malloc, 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. */
+extern void re_set_registers
+ _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+ unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+/* 4.2 bsd compatibility. */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+
+/* POSIX compatibility. */
+extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
+extern int regexec
+ _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags));
+extern size_t regerror
+ _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
+ size_t errbuf_size));
+extern void regfree _RE_ARGS ((regex_t *preg));
+
+#endif /* not __REGEXP_LIBRARY_H__ */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/gnu/usr.bin/grep/search.c b/gnu/usr.bin/grep/search.c
new file mode 100644
index 0000000..d2be489
--- /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
+
+#ifdef isascii
+#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 "regex.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/regress.sh b/gnu/usr.bin/grep/tests/regress.sh
new file mode 100644
index 0000000..b947036
--- /dev/null
+++ b/gnu/usr.bin/grep/tests/regress.sh
@@ -0,0 +1,30 @@
+#! /bin/sh
+# Regression test for GNU e?grep.
+# Usage: regress.sh [dir-containing-egrep]
+
+builddir=${1-..}
+
+failures=0
+
+# The Khadafy test is brought to you by Scott Anderson . . .
+$builddir/egrep -f khadafy.regexp khadafy.lines > khadafy.out
+if cmp khadafy.lines khadafy.out
+then
+ rm khadafy.out
+else
+ echo Khadafy test failed -- output left on khadafy.out
+ failures=1
+fi
+
+# . . . and the following by Henry Spencer.
+
+awk -F: -f scriptgen.awk spencer.tests > tmp.script
+
+if sh tmp.script $builddir
+then
+ rm tmp.script
+ exit $failures
+else
+ rm tmp.script
+ exit 1
+fi
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/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..e6f8652
--- /dev/null
+++ b/gnu/usr.bin/gzip/Makefile
@@ -0,0 +1,26 @@
+# @(#)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
+CFLAGS+=-DASMV -DSTDC_HEADERS=1 -DHAVE_UNISTD_H=1 -DDIRENT=1
+MLINKS= gzip.1 gunzip.1 gzip.1 zcat.1 gzip.1 gzcat.1
+LINKS+= ${BINDIR}/gzip ${BINDIR}/gunzip
+LINKS+= ${BINDIR}/gzip ${BINDIR}/gzcat
+LINKS+= ${BINDIR}/gzip ${BINDIR}/zcat
+NOSHARED=yes
+
+afterinstall:
+ 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..544d6da
--- /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 0.9 1993/06/11 10:16:58 jloup 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..7f52b64
--- /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 0.15 1993/06/24 10:53:53 jloup 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/gzexe.in b/gnu/usr.bin/gzip/gzexe.in
new file mode 100644
index 0000000..a28ec3d
--- /dev/null
+++ b/gnu/usr.bin/gzip/gzexe.in
@@ -0,0 +1,151 @@
+:
+#!/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 | "BINDIR"/gzip -cd > /tmp/gztmp$$; then
+ /bin/chmod 700 /tmp/gztmp$$
+ prog="`echo $0 | /bin/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
+ "BINDIR"/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" | "BINDIR"/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/gzip.1 b/gnu/usr.bin/gzip/gzip.1
new file mode 100644
index 0000000..084dffd
--- /dev/null
+++ b/gnu/usr.bin/gzip/gzip.1
@@ -0,0 +1,478 @@
+.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), zip(1), unzip(1), compress(1),
+pack(1), compact(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..09fe9a1
--- /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 0.24 1993/06/24 10:52:07 jloup 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..88b0710
--- /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..ede3656
--- /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 0.14 1993/06/10 13:27:04 jloup 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..a97d8be
--- /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 0.18 1993/06/14 19:32:20 jloup 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..db3b4b7
--- /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 0.12 1993/06/10 13:27:54 jloup 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..15d2a31
--- /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 0.15 1993/06/10 13:28:35 jloup 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..70375d8
--- /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 0.15 1993/06/15 09:04:13 jloup 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/zcmp b/gnu/usr.bin/gzip/zcmp
new file mode 100644
index 0000000..c21e7ef
--- /dev/null
+++ b/gnu/usr.bin/gzip/zcmp
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+# 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.
+
+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 -cd "$2" > /tmp/"$F".$$
+ gzip -cd "$1" | $comp $OPTIONS - /tmp/"$F".$$
+ STAT="$?"
+ /bin/rm -f /tmp/"$F".$$;;
+
+ *) gzip -cd "$1" | $comp $OPTIONS - "$2"
+ STAT="$?";;
+ esac;;
+ *) case "$2" in
+ *[-.]gz | *[-.][zZ] | *.t[ga]z)
+ gzip -cd "$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 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..1cac6d7
--- /dev/null
+++ b/gnu/usr.bin/ld/Makefile
@@ -0,0 +1,19 @@
+# $Id: Makefile,v 1.13 1993/12/04 00:52:54 jkh Exp $
+#
+
+PROG= ld
+SRCS= ld.c symbol.c lib.c shlib.c warnings.c etc.c rrs.c xbits.c md.c
+CFLAGS += -D__FreeBSD__ -I$(.CURDIR) -I$(.CURDIR)/$(MACHINE)
+
+LDADD+= -lgnumalloc
+DPADD+= /usr/lib/libgnumalloc.a
+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/TODO b/gnu/usr.bin/ld/TODO
new file mode 100644
index 0000000..d37a245
--- /dev/null
+++ b/gnu/usr.bin/ld/TODO
@@ -0,0 +1,4 @@
+- Make C++ shared libs work (properly resolve ctor and dtor lists)
+- Make -r and -X work together for PIC .o files.
+
+- Avoid duplicatating shared library specifications in link_objects
diff --git a/gnu/usr.bin/ld/cplus-dem.c b/gnu/usr.bin/ld/cplus-dem.c
new file mode 100644
index 0000000..808db5e
--- /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.2 1993/08/01 18:46:58 mycroft 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..4741685
--- /dev/null
+++ b/gnu/usr.bin/ld/i386/md-static-funcs.c
@@ -0,0 +1,17 @@
+/*
+ * $Id: md-static-funcs.c,v 1.2 1993/12/08 10:14:44 pk Exp $
+ *
+ * Called by ld.so when onanating.
+ * 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;
+{
+if (r->r_relative)
+ *(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..ce61355
--- /dev/null
+++ b/gnu/usr.bin/ld/i386/md.c
@@ -0,0 +1,357 @@
+/*
+ * 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.9 1994/02/13 20:42:09 jkh 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);
+ }
+ errx(1, "Unsupported relocation size: %x", RELOC_TARGET_SIZE(rp));
+ return 0;
+}
+
+/*
+ * 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);
+ return;
+ case 1:
+ put_short(addr, relocation);
+ return;
+ case 2:
+ put_long(addr, relocation);
+ return;
+ }
+ 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)) /*WAS: if (entry_symbol) */
+ 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 & 0xffffff00);
+ 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 << 1) & 6);
+ bits |= ((r->r_extern << 3) & 8);
+ bits |= ((r->r_baserel << 4) & 0x10);
+ bits |= ((r->r_jmptable << 5) & 0x20);
+ bits |= ((r->r_relative << 6) & 0x40);
+#ifdef N_SIZE
+ bits |= ((r->r_copy << 7) & 0x80);
+#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..1209aee
--- /dev/null
+++ b/gnu/usr.bin/ld/i386/md.h
@@ -0,0 +1,257 @@
+/*
+ * 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.9 1994/02/13 20:42:11 jkh 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
+
+#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/i386/mdprologue.S b/gnu/usr.bin/ld/i386/mdprologue.S
new file mode 100644
index 0000000..6a582be
--- /dev/null
+++ b/gnu/usr.bin/ld/i386/mdprologue.S
@@ -0,0 +1,124 @@
+/*
+ * 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 1993/12/10 10:16:00 jkh Exp $
+ */
+
+/*
+ * i386 run-time link editor entry points.
+ */
+
+#include <sys/syscall.h>
+#define LCALL(x,y) .byte 0x9a ; .long y; .word x
+
+ .text
+ .globl _binder, _binder_entry
+
+/*
+ * _rtl(int version, struct crt_ldso *crtp)
+ */
+#define FRAME 12 /* Size of stack frame */
+
+
+_rtl: # crt0 calls us here
+ pushl %ebp # Allocate stack frame
+ movl %esp, %ebp
+ subl $FRAME, %esp
+ 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
+
+ movl (-FRAME-4)(%ebp), %ebx # restore %ebx
+ leave # remove stack frame,
+ ret # lets rock
+
+ # 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
+
+ movl $0, %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
+
+ # Special system call stubs which return real and effective user and group
+ # ids. Saves overhead of making separate calls for each.
+ # !! Relies on compatability option in BSD 4.three-and-a-half
+
+ .globl _getreuid, _getregid
+_getreuid:
+ lea SYS_getuid, %eax
+ LCALL(7,0)
+ jc out
+ movl 4(%esp), %ecx # get 1st arg
+ movl %eax, (%ecx) # put value in it
+ movl 8(%esp), %ecx # same for 2nd arg
+ movl %edx, (%ecx) #
+ ret # done
+
+_getregid:
+ lea SYS_getgid, %eax
+ LCALL(7,0)
+ jc out
+ movl 4(%esp), %ecx # get 1st arg
+ movl %eax, (%ecx) # put value in it
+ movl 8(%esp), %ecx # same for 2nd arg
+ movl %edx, (%ecx) #
+ ret # done
+
+out: jmp cerror@PLT # Call common error routine
+
diff --git a/gnu/usr.bin/ld/ld.1 b/gnu/usr.bin/ld/ld.1
new file mode 100644
index 0000000..efbe7ee
--- /dev/null
+++ b/gnu/usr.bin/ld/ld.1
@@ -0,0 +1,207 @@
+.\"
+.\" 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.6 1994/03/09 14:28:02 davidg Exp $
+.\"
+.Dd October 14, 1993
+.Dt LD 8
+.Os FreeBSD 1.1
+.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 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 o Ar filename
+Specifies the name of the output file. Defaults to
+.Dq a.out.
+.It Fl Q
+Make a BSD/386 / FreeBSD 1.1 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 0.9 ZMAGIC output file.
+.Sh FILES
+.Sh SEE ALSO
+.Xr ldconfig 1 ,
+.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..efbe7ee
--- /dev/null
+++ b/gnu/usr.bin/ld/ld.1aout
@@ -0,0 +1,207 @@
+.\"
+.\" 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.6 1994/03/09 14:28:02 davidg Exp $
+.\"
+.Dd October 14, 1993
+.Dt LD 8
+.Os FreeBSD 1.1
+.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 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 o Ar filename
+Specifies the name of the output file. Defaults to
+.Dq a.out.
+.It Fl Q
+Make a BSD/386 / FreeBSD 1.1 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 0.9 ZMAGIC output file.
+.Sh FILES
+.Sh SEE ALSO
+.Xr ldconfig 1 ,
+.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..3cb49d2
--- /dev/null
+++ b/gnu/usr.bin/ld/ld.c
@@ -0,0 +1,3513 @@
+/*-
+ * 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.21 1994/02/17 03:57:00 davidg 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. */
+int outdesc; /* 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 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.
+ */
+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 warning_count; /* # of warning symbols encountered. */
+
+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;
+ warning_count = 0;
+ multiple_def_count = 0;
+ common_defined_global_count = 0;
+
+ /* Keep a list of symbols referenced from the command line */
+ cl_refs_allocated = 10;
+ cmdline_references = (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);
+
+ /* Prepare for the run-time linking support. */
+ init_rrs();
+
+ /*
+ * 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");
+
+ 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, "-T argument not multiple of page size, with sharable output");
+
+ /* Append the standard search directories to the user-specified ones. */
+ add_search_path(getenv("LD_LIBRARY_PATH"));
+ if (!nostdlib && getenv("LD_NOSTD_PATH") == NULL)
+ 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 number", 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) failed", 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) failed",
+ 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 failed",
+ 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 failed",
+ 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;
+ }
+ entry->flags |= E_DYNAMIC;
+ if (entry->superfile || rrs_add_shobj(entry))
+ read_shared_object(fd, entry);
+ else
+ entry->flags |= E_SCRAPPED;
+ } else {
+ 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 *name = p->n_un.n_strx + entry->strings;
+
+ /* Grab the next entry. */
+ p++;
+ if (p->n_type != (N_UNDF | N_EXT)) {
+ warnx(
+ "%s: Warning symbol without external reference following.",
+ get_file_name(entry));
+ make_executable = 0;
+ p--; /* Process normally. */
+ } else {
+ symbol *sp;
+ char *sname = p->n_un.n_strx + entry->strings;
+ /* Deal with the warning symbol. */
+ enter_global_ref(lsp,
+ p->n_un.n_strx + entry->strings, entry);
+ sp = getsym (sname);
+ sp->warning = (char *)xmalloc(strlen(name)+1);
+ strcpy (sp->warning, name);
+ warning_count++;
+ }
+ } else if (p->n_type & N_EXT) {
+ enter_global_ref(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)) {
+ 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 (entry->flags & E_DYNAMIC) {
+ lsp->next = sp->sorefs;
+ sp->sorefs = lsp;
+
+ /*
+ * 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...
+ */
+ sp->common_size = 0;
+ sp->defined = 0;
+ }
+
+ /*
+ * Handle size information in shared objects.
+ */
+ if (nzp->nz_size > sp->size)
+ sp->size = nzp->nz_size;
+
+ lsp->symbol = sp;
+ return;
+ }
+
+ lsp->next = sp->refs;
+ sp->refs = lsp;
+ lsp->symbol = sp;
+
+ 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;
+ }
+
+#ifdef N_SIZE
+ 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
+#endif
+ 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 (oldref && !olddef)
+ /*
+ * It used to be undefined and we're defining it.
+ */
+ undefined_global_sym_count--;
+ if (undefined_global_sym_count < 0)
+ errx(1,
+ "internal error: enter_glob_ref: undefined_global_sym_count = %d",
+ undefined_global_sym_count);
+
+ 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 (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;
+
+ default:
+ reftype = "I don't know this type";
+ break;
+ }
+
+ fprintf(stderr, "symbol %s %s in ", sp->name, 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;
+
+ if (relocatable_output)
+ /* We write out the original N_SET* symbols */
+ global_sym_count += size_sym_count;
+
+#ifdef DEBUG
+printf("global symbols %d (defined %d, undefined %d, aliases %d), locals: %d, \
+debug symbols: %d, set_symbols %d\n",
+ global_sym_count,
+ defined_global_sym_count, undefined_global_sym_count, global_alias_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) {
+ 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_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 (defs++ && sp->value != p->n_value
+ && entry_symbol/*XXX*/) {
+ sp->mult_defs = 1;
+ multiple_def_count++;
+ }
+ sp->def_nlist = p;
+ 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;
+ }
+
+ 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_nlist = p;
+ lsp->entry->flags |= E_SYMBOLS_USED;
+ sp->so_defined = type;
+ sp->aux = N_AUX(p);
+ if (sp->flags & GS_REFERENCED)
+ undefined_global_sym_count--;
+ else
+ sp->flags |= GS_REFERENCED;
+#ifdef DEBUG
+printf("shr: %s gets defined to %x with value %x\n", sp->name, type, sp->value);
+#endif
+ 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;
+ }
+ break;
+ }
+ }
+ } 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;
+ 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: internal error, sp==NULL",
+ 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)
+ 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.
+ */
+ 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_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->defined && sp->def_nlist &&
+ ((sp->defined & ~N_EXT) != N_SETV))
+ sp->value = sp->def_nlist->n_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 (!(size & align))
+ align <<= 1;
+
+ align = align > MAX_ALIGNMENT ? MAX_ALIGNMENT : align;
+
+ 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;
+
+ if (lstat(output_filename, &statbuf) == 0) {
+ if (S_ISREG(statbuf.st_mode))
+ (void)unlink(output_filename);
+ }
+
+ outdesc = open(output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (outdesc < 0)
+ err(1, "open: %s", output_filename);
+
+ if (atexit(cleanup))
+ err(1, "atexit");
+
+ if (fstat (outdesc, &statbuf) < 0)
+ err(1, "fstat: %s", output_filename);
+
+ filemode = statbuf.st_mode;
+
+ chmod (output_filename, filemode & ~0111);
+
+ /* Output the a.out header. */
+ write_header();
+
+ /* Output the text and data segments, relocating as we go. */
+ write_text();
+ write_data();
+
+ /* Output the merged relocation info, if requested with `-r'. */
+ if (relocatable_output)
+ write_rel();
+
+ /* Output the symbol table (both globals and locals). */
+ write_syms();
+
+ /* Output the RSS section */
+ write_rrs();
+
+ if (chmod (output_filename, filemode | 0111) == -1)
+ err(1, "chmod: %s", output_filename);
+
+ close(outdesc);
+ outdesc = 0;
+}
+
+/* Total number of symbols to be written in the output file. */
+static int nsyms;
+
+void
+write_header()
+{
+ int flags = (rrs_section_type == RRS_FULL) ? EX_DYNAMIC : 0;
+
+ if (oldmagic && (flags & EX_DYNAMIC))
+ 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, outdesc);
+ 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, outdesc);
+#endif
+}
+
+/*
+ * Relocate the text segment of each input file
+ * and write to the output file.
+ */
+void
+write_text()
+{
+
+ if (trace_files)
+ fprintf(stderr, "Copying and relocating text:\n\n");
+
+ each_full_file(copy_text, 0);
+ file_close();
+
+ if (trace_files)
+ fprintf(stderr, "\n");
+
+ padfile(text_pad, outdesc);
+}
+
+/*
+ * 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 in text section", 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, outdesc);
+}
+
+/*
+ * 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 (lseek(outdesc, pos, L_SET) != pos)
+ errx(1, "write_data: failed to lseek to data offset");
+
+ 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), outdesc);
+ }
+
+ if (trace_files)
+ fprintf(stderr, "\n");
+
+ padfile(data_pad, outdesc);
+}
+
+/*
+ * Read the data segment contents of ENTRY, relocate them, and write the
+ * result to the output file. If `-r', save the data relocation for later
+ * reuse. See comments in `copy_text'.
+ */
+void
+copy_data(entry)
+ struct file_entry *entry;
+{
+ register 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 in data section", get_file_name(entry));
+
+ perform_relocation(bytes, entry->header.a_data,
+ entry->datarel, entry->ndatarel, entry, 1);
+
+ mywrite(bytes, 1, entry->header.a_data, outdesc);
+}
+
+/*
+ * Relocate ENTRY's text or data section contents. DATA is the address of the
+ * contents, in core. DATA_SIZE is the length of the contents. PC_RELOCATION
+ * is the difference between the address of the contents in the output file
+ * and its address in the input file. RELOC 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->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->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->jmpslot_offset != -1)?
+ " (JMPSLOT)":"");
+ }
+ if (sp->so_defined == (N_TEXT+N_EXT) &&
+ sp->jmpslot_offset != -1) {
+ /*
+ * 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 (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 && (sp->flags & GS_REFERENCED)) {
+ 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), outdesc);
+}
+
+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), outdesc);
+}
+
+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 symbol_table_offset;
+static int symbol_table_len;
+
+/* Address in output file where string table starts. */
+static int string_table_offset;
+
+/* Offset within string table
+ where the strings in `strtab_vector' should be written. */
+static int string_table_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;
+}
+
+FILE *outstream = (FILE *)0;
+
+/*
+ * Write the contents of `strtab_vector' into the string table. This is done
+ * once for each file's local&debugger symbols and once for the global
+ * symbols.
+ */
+void
+write_string_table()
+{
+ register int i;
+
+ if (lseek(outdesc, string_table_offset + string_table_len, 0) ==
+ (off_t)-1)
+ err(1, "write_string_table: %s: lseek", output_filename);
+
+ if (!outstream)
+ outstream = fdopen(outdesc, "w");
+
+ for (i = 0; i < strtab_index; i++) {
+ fwrite (strtab_vector[i], 1, strtab_lens[i], outstream);
+ string_table_len += strtab_lens[i];
+ }
+
+ fflush(outstream);
+
+ /* Report I/O error such as disk full. */
+ if (ferror(outstream))
+ err(1, "write_string_table: %s", output_filename);
+}
+
+/* Write the symbol table and string table of the output file. */
+
+void
+write_syms()
+{
+ /* Number of symbols written so far. */
+ int syms_written = 0;
+ 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;
+
+ symbol_table_offset = N_SYMOFF(outheader);
+ symbol_table_len = 0;
+ string_table_offset = N_STROFF(outheader);
+ string_table_len = strtab_size;
+
+ if (strip_symbols == STRIP_ALL)
+ return;
+
+ /* 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;
+
+ 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)
+ warnx("symbol %s remains undefined", sp->name);
+ continue;
+ }
+
+ 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 {
+ 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;
+ nl.n_other = N_OTHER(0, 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 (lseek(outdesc, symbol_table_offset + symbol_table_len, 0) ==
+ (off_t)-1)
+ err(1, "write_syms: lseek");
+ md_swapout_symbols(buf, bufp - buf);
+ mywrite(buf, bufp - buf, sizeof(struct nlist), outdesc);
+ symbol_table_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 (symbol_table_offset + symbol_table_len != string_table_offset)
+ errx(1,
+ "internal error: inconsistent symbol table length: %d vs %s",
+ symbol_table_offset + symbol_table_len, string_table_offset);
+
+ lseek(outdesc, string_table_offset, 0);
+ strtab_size = md_swap_long(strtab_size);
+ mywrite(&strtab_size, sizeof(int), 1, outdesc);
+}
+
+
+/*
+ * 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. */
+
+ lseek(outdesc, symbol_table_offset + symbol_table_len, 0);
+ md_swapout_symbols(buf, bufp - buf);
+ mywrite(buf, bufp - buf, sizeof(struct nlist), outdesc);
+ symbol_table_len += sizeof(struct nlist) * (bufp - buf);
+
+ /*
+ * Write the string-table data for the symbols just written, using
+ * the data in vectors `strtab_vector' and `strtab_lens'.
+ */
+
+ write_string_table();
+ entry->strings = 0; /* Since it will 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;
+ int fd;
+{
+ register int val;
+ register int bytes = count * eltsize;
+
+ while (bytes > 0) {
+ val = write(fd, buf, bytes);
+ if (val <= 0)
+ err(1, "write: %s", output_filename);
+ buf += val;
+ bytes -= val;
+ }
+}
+
+static void
+cleanup()
+{
+ struct stat statbuf;
+
+ if (outdesc <= 0)
+ return;
+
+ if (fstat(outdesc, &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;
+ int 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..3c1b195
--- /dev/null
+++ b/gnu/usr.bin/ld/ld.h
@@ -0,0 +1,688 @@
+/*
+ * $Id: ld.h,v 1.10 1994/02/13 20:41:34 jkh 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
+
+#ifdef __FreeBSD__
+#define FreeBSD
+#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)
+
+#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__ */
+
+
+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_GOTSLOTCLAIMED 8 /* This symbol has a GOT entry */
+} 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 */
+
+ struct nlist *def_nlist; /* 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 1 /* Symbol has definition (notyetused)*/
+#define GS_REFERENCED 2 /* Symbol is referred to by something
+ interesting */
+#define GS_TRACE 4 /* Symbol will be traced */
+#define GS_JMPSLOTCLAIMED 8 /* */
+#define GS_GOTSLOTCLAIMED 0x10 /* Some state bits concerning */
+#define GS_CPYRELOCRESERVED 0x20 /* entries in GOT and PLT tables */
+#define GS_CPYRELOCCLAIMED 0x40 /* */
+
+} 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 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 warning_count;
+
+/*
+ * Define a linked list of strings which define symbols which should be
+ * treated as set elements even though they aren't. Any symbol with a prefix
+ * matching one of these should be treated as a set element.
+ *
+ * This is to make up for deficiencies in many assemblers which aren't willing
+ * to pass any stabs through to the loader which they don't understand.
+ */
+struct string_list_element {
+ char *str;
+ struct string_list_element *next;
+};
+
+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 */
+};
+
+/*
+ * 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 int outdesc; /* Output file descriptor. */
+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, int));
+void padfile __P((int,int));
+
+/* 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));
+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..1ca25a4
--- /dev/null
+++ b/gnu/usr.bin/ld/ldconfig/ldconfig.8
@@ -0,0 +1,102 @@
+.Dd October 3, 1993
+.Dt LDCONFIG 8
+.Os FreeBSD 1.1
+.Sh NAME
+.Nm ldconfig
+.Nd configure the shared library cache
+.Sh SYNOPSIS
+.Nm ldconfig
+.Op Fl rsv
+.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 forstall 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 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
+.Nm ldconfig
+\'s builtin system directories
+.Sq /usr/lib
+,
+.Sq /usr/X386/lib
+,
+.Sq /usr/X11R6/lib
+and
+.Sq /usr/local/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..b31271f
--- /dev/null
+++ b/gnu/usr.bin/ld/ldconfig/ldconfig.c
@@ -0,0 +1,429 @@
+/*
+ * 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.6 1994/06/05 19:04:11 ats 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
+
+char *progname;
+static int verbose;
+static int nostd;
+static int justread;
+
+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 build_hints __P((void));
+static int listhints __P((void));
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int i, c;
+ int rval = 0;
+ extern int optind;
+
+ if ((progname = strrchr(argv[0], '/')) == NULL)
+ progname = argv[0];
+ else
+ progname++;
+
+ while ((c = getopt(argc, argv, "rsv")) != EOF) {
+ switch (c) {
+ case 'v':
+ verbose = 1;
+ break;
+ case 's':
+ nostd = 1;
+ break;
+ case 'r':
+ justread = 1;
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [-r] [-s] [-v] [dir ...]\n", progname);
+ exit(1);
+ break;
+ }
+ }
+
+ if (justread)
+ return listhints();
+
+ 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 |= build_hints();
+
+ 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)
+ perror(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, vminor)
+char *cp;
+int vmajor, vminor;
+{
+ int k = 0;
+
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
+ k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff;
+
+ return k;
+}
+
+int
+build_hints()
+{
+ 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, shp->minor) % 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) {
+ fprintf(stderr, "Bummer!\n");
+ 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;
+ }
+
+ tmpfile = concat(_PATH_LD_HINTS, "+", "");
+ if ((fd = open(tmpfile, O_RDWR|O_CREAT|O_TRUNC, 0444)) == -1) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+
+ if (write(fd, &hdr, sizeof(struct hints_header)) !=
+ sizeof(struct hints_header)) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+ if (write(fd, blist, hdr.hh_nbucket * sizeof(struct hints_bucket)) !=
+ hdr.hh_nbucket * sizeof(struct hints_bucket)) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+ if (write(fd, strtab, strtab_sz) != strtab_sz) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+ if (close(fd) != 0) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+
+ /* Install it */
+ if (unlink(_PATH_LD_HINTS) != 0 && errno != ENOENT) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+
+ if (rename(tmpfile, _PATH_LD_HINTS) != 0) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+listhints()
+{
+ int fd;
+ caddr_t addr;
+ long msize;
+ struct hints_header *hdr;
+ struct hints_bucket *blist;
+ char *strtab;
+ int i;
+
+ if ((fd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+
+ msize = PAGSIZ;
+ addr = mmap(0, msize, PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
+
+ if (addr == (caddr_t)-1) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+
+ hdr = (struct hints_header *)addr;
+ if (HH_BADMAG(*hdr)) {
+ fprintf(stderr, "%s: Bad magic: %o\n",
+ _PATH_LD_HINTS, hdr->hh_magic);
+ return -1;
+ }
+
+ if (hdr->hh_version != LD_HINTS_VERSION_1) {
+ fprintf(stderr, "Unsupported version: %d\n", hdr->hh_version);
+ return -1;
+ }
+
+ if (hdr->hh_ehints > msize) {
+ if (mmap(addr+msize, hdr->hh_ehints - msize,
+ PROT_READ, MAP_FILE|MAP_COPY|MAP_FIXED,
+ fd, msize) != (caddr_t)(addr+msize)) {
+
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+ }
+ close(fd);
+
+ blist = (struct hints_bucket *)(addr + hdr->hh_hashtab);
+ strtab = (char *)(addr + hdr->hh_strtab);
+
+ printf("%s:\n", _PATH_LD_HINTS);
+ for (i = 0; i < hdr->hh_nbucket; i++) {
+ struct hints_bucket *bp = &blist[i];
+
+ /* Sanity check */
+ if (bp->hi_namex >= hdr->hh_strtab_sz) {
+ fprintf(stderr, "Bad name index: %#x\n", bp->hi_namex);
+ return -1;
+ }
+ if (bp->hi_pathx >= hdr->hh_strtab_sz) {
+ fprintf(stderr, "Bad path index: %#x\n", bp->hi_pathx);
+ return -1;
+ }
+
+ printf("\t%d:-l%s.%d.%d => %s (%d -> %d)\n",
+ i,
+ strtab + bp->hi_namex, bp->hi_major, bp->hi_minor,
+ strtab + bp->hi_pathx,
+ hinthash(strtab+bp->hi_namex, bp->hi_major, bp->hi_minor)
+ % hdr->hh_nbucket,
+ bp->hi_next);
+ }
+
+ return 0;
+}
+
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..13a13ee
--- /dev/null
+++ b/gnu/usr.bin/ld/ldd/ldd.1
@@ -0,0 +1,24 @@
+.Dd October 22, 1993
+.Dt LDD 1
+.Os FreeBSD 1.1
+.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 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..1072d80
--- /dev/null
+++ b/gnu/usr.bin/ld/ldd/ldd.c
@@ -0,0 +1,136 @@
+/*
+ * 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.3 1994/02/13 20:42:43 jkh 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_DYNAMIC) ||
+ hdr.a_entry < __LDPGSZ) {
+
+ 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..7eaaa98
--- /dev/null
+++ b/gnu/usr.bin/ld/lib.c
@@ -0,0 +1,843 @@
+/*
+ * $Id: lib.c,v 1.9 1994/02/13 20:41:37 jkh 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 (!(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 (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 (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\n",
+ sp->name);
+ }
+ 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;
+
+ 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..a0627e7
--- /dev/null
+++ b/gnu/usr.bin/ld/rrs.c
@@ -0,0 +1,1179 @@
+/*
+ * 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.11 1994/02/13 20:41:40 jkh 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 number_of_gotslots;
+static int number_of_jmpslots;
+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 current_reloc_offset;
+static int current_hash_index;
+int number_of_shobjs;
+
+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 |
+ | |
+ +-------------------+ <-- _GLOBAL_OFFSET_TABLE_ (sdt_got)
+ | |
+ | _GOT_ |
+ | |
+ +-------------------+ <-- sdt_plt
+ | |
+ | PLT |
+ | |
+ +-------------------+
+*/
+
+/*
+ * Initialize RRS
+ */
+
+void
+init_rrs()
+{
+ reserved_rrs_relocs = 0;
+ claimed_rrs_relocs = 0;
+
+ number_of_rrs_symbols = 0;
+ rrs_strtab_size = 0;
+
+ /* First jmpslot reserved for run-time binder */
+ current_jmpslot_offset = sizeof(jmpslot_t);
+ number_of_jmpslots = 1;
+
+ /* First gotslot reserved for __DYNAMIC */
+ current_got_offset = sizeof(got_t);
+ number_of_gotslots = 1;
+
+ current_reloc_offset = 0;
+}
+
+/*
+ * 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->jmpslot_offset == -1) {
+ sp->jmpslot_offset = current_jmpslot_offset;
+ current_jmpslot_offset += sizeof(jmpslot_t);
+ number_of_jmpslots++;
+ if (!(link_mode & SYMBOLIC) || JMPSLOT_NEEDS_RELOC) {
+ 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->gotslot_offset == -1) {
+ lsp->gotslot_offset = current_got_offset;
+ current_got_offset += sizeof(got_t);
+ number_of_gotslots++;
+ /*
+ * Now, see if slot needs run-time fixing
+ * If the load address is known (entry_symbol), this
+ * slot will have its final value set by `claim_got'
+ */
+ if ((link_mode & SHAREABLE) || (link_mode & SYMBOLIC))
+ reserved_rrs_relocs++;
+ }
+
+ } 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->gotslot_offset != -1)
+ return;
+
+ /*
+ * External symbols always get a relocation entry
+ */
+ sp->gotslot_offset = current_got_offset;
+ reserved_rrs_relocs++;
+ current_got_offset += sizeof(got_t);
+ number_of_gotslots++;
+ }
+
+}
+
+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_JMPSLOTCLAIMED)
+ return rrs_sdt.sdt_plt + sp->jmpslot_offset;
+
+#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 (sp->jmpslot_offset == -1)
+ errx(1,
+ "internal error: %s: claim_rrs_jmpslot: %s: jmpslot_offset == -1\n",
+ get_file_name(entry),
+ sp->name);
+
+ 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 (!JMPSLOT_NEEDS_RELOC) {
+ 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);
+ }
+
+ if (rrs_section_type == RRS_PARTIAL)
+ /* PLT is self-contained */
+ return rrs_sdt.sdt_plt + sp->jmpslot_offset;
+
+ /*
+ * Install a run-time relocation for this PLT entry.
+ */
+ r = rrs_next_reloc();
+ sp->flags |= GS_JMPSLOTCLAIMED;
+
+ 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;
+
+#ifdef DEBUG
+printf("claim_rrs_gotslot: %s(%d) slot offset %#x, addend %#x\n",
+ sp->name, sp->rrs_symbolnum, sp->gotslot_offset, addend);
+#endif
+ if (sp->gotslot_offset == -1)
+ errx(1,
+ "internal error: %s: claim_rrs_gotslot: %s: gotslot_offset == -1\n",
+ get_file_name(entry), sp->name);
+
+ if (sp->flags & GS_GOTSLOTCLAIMED)
+ /* This symbol already passed here before. */
+ return sp->gotslot_offset;
+
+ if (sp->defined &&
+ (!(link_mode & SHAREABLE) || (link_mode & SYMBOLIC))) {
+
+ /*
+ * Reduce to just a base-relative translation.
+ */
+
+ *(got_t *)((long)rrs_got + 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-rime.
+ */
+
+ *(got_t *)((long)rrs_got + 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));
+ 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();
+ sp->flags |= GS_GOTSLOTCLAIMED;
+ r->r_address = rrs_sdt.sdt_got + 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 - rrs_sdt.sdt_got;
+
+#ifdef DEBUG
+printf("claim_rrs_internal_gotslot: %s: slot offset %#x, addend = %#x\n",
+ get_file_name(entry), lsp->gotslot_offset, addend);
+#endif
+
+ if (lsp->gotslot_offset == -1)
+ errx(1,
+ "internal error: %s: claim_rrs_internal_gotslot at %#x: slot_offset == -1\n",
+ get_file_name(entry), RELOC_ADDRESS(rp));
+
+ if (lsp->flags & LS_GOTSLOTCLAIMED)
+ /* Already done */
+ return lsp->gotslot_offset;
+
+ *(long *)((long)rrs_got + lsp->gotslot_offset) = addend;
+
+ if (!(link_mode & SHAREABLE))
+ return lsp->gotslot_offset;
+
+ /*
+ * Relocation entry needed for this static GOT entry.
+ */
+ r = rrs_next_reloc();
+ lsp->flags |= LS_GOTSLOTCLAIMED;
+ r->r_address = rrs_sdt.sdt_got + 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\n",
+ 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;
+ 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
+ * Assign number 0 to __DYNAMIC (!! Sun compatibility)
+ */
+ dynamic_symbol->rrs_symbolnum = number_of_rrs_symbols++;
+ FOR_EACH_SYMBOL(i ,sp) {
+ if (sp->flags & GS_REFERENCED) {
+ 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;
+
+ if (rrs_section_type == RRS_NONE)
+ return;
+
+ if (rrs_section_type == RRS_PARTIAL) {
+ got_symbol->value = rrs_sdt.sdt_got = rrs_data_start;
+ 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
+ * &__DYNAMIC is also in the first GOT entry.
+ */
+ got_symbol->value = rrs_sdt.sdt_got;
+
+ *rrs_got = 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 (lseek(outdesc, pos, L_SET) != pos)
+ err(1, "write_rrs_data: lseek");
+
+ if (rrs_section_type == RRS_PARTIAL) {
+ /*
+ * Only a GOT and PLT are needed.
+ */
+ if (number_of_gotslots <= 1)
+ errx(1, "write_rrs_data: # gotslots <= 1");
+
+ md_swapout_got(rrs_got, number_of_gotslots);
+ mywrite(rrs_got, number_of_gotslots,
+ sizeof(got_t), outdesc);
+
+ if (number_of_jmpslots <= 1)
+ errx(1, "write_rrs_data: # jmpslots <= 1");
+
+ md_swapout_jmpslot(rrs_plt, number_of_jmpslots);
+ mywrite(rrs_plt, number_of_jmpslots,
+ sizeof(jmpslot_t), outdesc);
+ return;
+ }
+
+ md_swapout__dynamic(&rrs_dyn);
+ mywrite(&rrs_dyn, 1, sizeof(struct _dynamic), outdesc);
+
+ md_swapout_so_debug(&rrs_so_debug);
+ mywrite(&rrs_so_debug, 1, sizeof(struct so_debug), outdesc);
+
+ md_swapout_section_dispatch_table(&rrs_sdt);
+ mywrite(&rrs_sdt, 1, sizeof(struct section_dispatch_table), outdesc);
+
+ md_swapout_got(rrs_got, number_of_gotslots);
+ mywrite(rrs_got, number_of_gotslots, sizeof(got_t), outdesc);
+
+ md_swapout_jmpslot(rrs_plt, number_of_jmpslots);
+ mywrite(rrs_plt, number_of_jmpslots, sizeof(jmpslot_t), outdesc);
+}
+
+void
+write_rrs_text()
+{
+ long pos;
+ int i;
+ int symsize;
+ struct nzlist *nlp;
+ int offset = 0;
+ struct shobj *shp;
+ struct sod *sodp;
+
+ if (rrs_section_type == RRS_PARTIAL)
+ return;
+
+ pos = rrs_text_start + (N_TXTOFF(outheader) - TEXT_START(outheader));
+ if (lseek(outdesc, pos, L_SET) != pos)
+ err(1, "write_rrs_text: lseek");
+
+ /* Write relocation records */
+ md_swapout_reloc(rrs_reloc, reserved_rrs_relocs);
+ mywrite(rrs_reloc, reserved_rrs_relocs,
+ sizeof(struct relocation_info), outdesc);
+
+ /* 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), outdesc);
+
+ /*
+ * 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->flags & GS_REFERENCED) || sp == dynamic_symbol)
+ 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;
+
+ 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(0, 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(0, 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;
+ } else if (!sp->defined) {
+ /* undefined */
+ nlp->nz_type = N_UNDF | N_EXT;
+ nlp->nz_value = 0;
+ if (sp->so_defined && sp->jmpslot_offset != -1) {
+ /*
+ * Define a "weak" function symbol.
+ */
+ if (sp->aux != AUX_FUNC)
+ errx(1, "%s: non-function jmpslot",
+ sp->name);
+ nlp->nz_other = N_OTHER(0, 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, outdesc);
+
+ /* Write the strings */
+ mywrite(rrs_strtab, rrs_strtab_size, 1, outdesc);
+
+ /*
+ * 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), outdesc);
+
+ 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, outdesc);
+ }
+}
+
+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 %d, gotslots %d, jmpslots %d\n",
+ reserved_rrs_relocs, number_of_gotslots-1, number_of_jmpslots-1);
+#endif
+
+#if 0
+ /* Must fix this check: misses out when linking PIC code but no
+ shared object involved: reserved relocs are never claimed!
+ */
+ if (claimed_rrs_relocs != reserved_rrs_relocs) {
+ errx(1, "internal error: reserved relocs(%d) != claimed(%d)",
+ reserved_rrs_relocs, claimed_rrs_relocs);
+ printf("FIX:internal error: reserved relocs(%d) != claimed(%d)\n",
+ reserved_rrs_relocs, claimed_rrs_relocs);
+ }
+#endif
+
+ /* 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..d0884e2
--- /dev/null
+++ b/gnu/usr.bin/ld/rtld/Makefile
@@ -0,0 +1,25 @@
+# $Id: Makefile,v 1.9 1994/02/13 20:42:48 jkh Exp $
+
+PROG= ld.so
+SRCS= mdprologue.S rtld.c malloc.c shlib.c etc.c md.c
+NOMAN= noman
+LDDIR?= $(.CURDIR)/..
+#PICFLAG=-pic
+PICFLAG=-fpic
+CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE) $(PICFLAG) -DRTLD
+LDFLAGS+=-Bshareable -Bsymbolic -assert nosymbolic
+ASFLAGS+=-k
+LDADD+= -lc_pic -lgcc_pic
+BINDIR= /usr/libexec
+
+.SUFFIXES: .S
+
+.PATH: $(LDDIR) $(LDDIR)/$(MACHINE)
+
+$(PROG):
+ $(LD) -o $(PROG) $(LDFLAGS) $(OBJS) $(LDADD)
+
+.S.o:
+ ${CPP} ${.IMPSRC} | ${AS} ${ASFLAGS} -o ${.TARGET} -
+
+.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..b5c54f8
--- /dev/null
+++ b/gnu/usr.bin/ld/rtld/malloc.c
@@ -0,0 +1,482 @@
+/*
+ * 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.1 1994/02/13 20:44:09 jkh 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 getpagesize() NBPG
+#define NPOOLPAGES (32*1024/NBPG)
+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.c b/gnu/usr.bin/ld/rtld/rtld.c
new file mode 100644
index 0000000..96dd0fe
--- /dev/null
+++ b/gnu/usr.bin/ld/rtld/rtld.c
@@ -0,0 +1,1261 @@
+/*
+ * 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.16 1994/04/13 20:52:40 ats 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 <sys/errno.h>
+#include <sys/mman.h>
+#ifndef BSD
+#define MAP_COPY MAP_PRIVATE
+#define MAP_ANON 0
+#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 BSD /* Need do better than this */
+#define NEED_DEV_ZERO 1
+#endif
+
+/*
+ * Loader private data, hung off <so_map>->som_spd
+ */
+struct somap_private {
+ int spd_version;
+ struct so_map *spd_parent;
+ int spd_refcount;
+ int spd_flags;
+#define RTLD_MAIN 1
+#define RTLD_RTLD 2
+#define RTLD_DL 4
+
+#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)))
+
+/* 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";
+
+struct so_map *link_map_head, *main_map;
+struct so_map **link_map_tail = &link_map_head;
+struct rt_symbol *rt_symbol_head;
+
+static void *__dlopen __P((char *, int));
+static int __dlclose __P((void *));
+static void *__dlsym __P((void *, char *));
+static int __dlctl __P((void *, int, void *));
+
+static struct ld_entry ld_entry = {
+ __dlopen, __dlclose, __dlsym, __dlctl
+};
+
+ void xprintf __P((char *, ...));
+static void load_objects __P(( struct crt_ldso *,
+ struct _dynamic *));
+static struct so_map *map_object __P((struct sod *, struct so_map *));
+static struct so_map *alloc_link_map __P(( char *, struct sod *,
+ struct so_map *, caddr_t,
+ struct _dynamic *));
+static inline void check_text_reloc __P(( struct relocation_info *,
+ struct so_map *,
+ caddr_t));
+static void reloc_map __P((struct so_map *));
+static void reloc_copy __P((struct so_map *));
+static void init_map __P((struct so_map *, char *));
+static char *rtfindlib __P((char *, int, 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 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;
+{
+ int n;
+ int nreloc; /* # of ld.so relocations */
+ struct relocation_info *reloc;
+ struct so_debug *ddp;
+ 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;
+
+ /* Divide by hand to avoid possible use of library division routine */
+ for ( nreloc = 0, n = LD_RELSZ(dp);
+ n > 0;
+ n -= sizeof(struct relocation_info) ) nreloc++;
+
+
+ /* Relocate ourselves */
+ for ( reloc = (struct relocation_info *)(LD_REL(dp) + crtp->crt_ba);
+ nreloc;
+ nreloc--, reloc++) {
+
+ register long addr = reloc->r_address + crtp->crt_ba;
+
+ md_relocate_simple(reloc, crtp->crt_ba, addr);
+ }
+
+ __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");
+ unsetenv("LD_RUN_PATH"); /* In case we ever implement this */
+ }
+
+ /* Setup directory search */
+ add_search_path(getenv("LD_RUN_PATH"));
+ add_search_path(getenv("LD_LIBRARY_PATH"));
+ if (getenv("LD_NOSTD_PATH") == NULL)
+ std_search_path();
+
+ /* Load required objects into the process address space */
+ load_objects(crtp, dp);
+
+ /* Relocate all loaded objects according to their RRS segments */
+ for (smp = link_map_head; smp; smp = smp->som_next) {
+ if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD)
+ continue;
+ reloc_map(smp);
+ }
+
+ /* Copy any relocated initialized data. */
+ for (smp = link_map_head; smp; smp = smp->som_next) {
+ if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD)
+ continue;
+ reloc_copy(smp);
+ }
+
+ /* Call any object initialization routines. */
+ for (smp = link_map_head; smp; smp = smp->som_next) {
+ if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD)
+ continue;
+ init_map(smp, ".init");
+ }
+
+ /* Fill in some field 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;
+
+ 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 our file descriptor */
+ (void)close(crtp->crt_ldfd);
+ return 0;
+}
+
+
+static void
+load_objects(crtp, dp)
+struct crt_ldso *crtp;
+struct _dynamic *dp;
+{
+ struct so_map *smp;
+ int tracing = (int)getenv("LD_TRACE_LOADED_OBJECTS");
+
+ /* Handle LD_PRELOAD's here */
+
+ /* Make an entry for the main program */
+ smp = alloc_link_map(main_progname, (struct sod *)0, (struct so_map *)0,
+ (caddr_t)0, crtp->crt_dp);
+ LM_PRIVATE(smp)->spd_refcount++;
+ LM_PRIVATE(smp)->spd_flags |= RTLD_MAIN;
+
+ /* Make an entry for ourselves */
+ smp = alloc_link_map(us, (struct sod *)0, (struct so_map *)0,
+ (caddr_t)crtp->crt_ba, dp);
+ LM_PRIVATE(smp)->spd_refcount++;
+ LM_PRIVATE(smp)->spd_flags |= RTLD_RTLD;
+
+ for (smp = link_map_head; smp; smp = smp->som_next) {
+ struct sod *sodp;
+ long next = 0;
+
+ if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD)
+ continue;
+
+ if (smp->som_dynamic)
+ next = LD_NEED(smp->som_dynamic);
+
+ while (next) {
+ struct so_map *newmap;
+
+ sodp = (struct sod *)(LM_LDBASE(smp) + next);
+ if ((newmap = map_object(sodp, smp)) == NULL) {
+ if (!tracing) {
+ char *name = (char *)
+ (sodp->sod_name + LM_LDBASE(smp));
+ char *fmt = sodp->sod_library ?
+ "%s: lib%s.so.%d.%d" :
+ "%s: %s";
+ err(1, fmt, main_progname, name,
+ sodp->sod_major,
+ sodp->sod_minor);
+ }
+ newmap = alloc_link_map(NULL, sodp, smp, 0, 0);
+ }
+ LM_PRIVATE(newmap)->spd_refcount++;
+ next = sodp->sod_next;
+ }
+ }
+
+ if (! tracing)
+ return;
+
+ for (smp = link_map_head; smp; smp = smp->som_next) {
+ struct sod *sodp;
+ char *name, *path;
+
+ if ((sodp = smp->som_sod) == NULL)
+ continue;
+ name = sodp->sod_name + LM_LDBASE(LM_PARENT(smp));
+
+ if ((path = smp->som_path) == NULL)
+ path = "not found";
+
+ if (sodp->sod_library)
+ printf("\t-l%s.%d => %s (%p)\n", name,
+ sodp->sod_major, path, smp->som_addr);
+ else
+ printf("\t%s => %s (%p)\n", name, path, smp->som_addr);
+ }
+
+ exit(0);
+}
+
+/*
+ * Allocate a new link map for shared object NAME loaded at ADDR as a
+ * result of the presence of link object LOP in the link map PARENT.
+ */
+ 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;
+
+ smpp = (struct somap_private *)xmalloc(sizeof(struct somap_private));
+ smp = (struct so_map *)xmalloc(sizeof(struct so_map));
+ smp->som_next = NULL;
+ *link_map_tail = smp;
+ link_map_tail = &smp->som_next;
+
+ smp->som_addr = addr;
+ smp->som_path = strdup(path);
+ smp->som_sod = sodp;
+ smp->som_dynamic = dp;
+ smp->som_spd = (caddr_t)smpp;
+
+/*XXX*/ if (addr == 0) main_map = smp;
+
+ smpp->spd_refcount = 0;
+ smpp->spd_flags = 0;
+ smpp->spd_parent = parent;
+
+#ifdef SUN_COMPAT
+ smpp->spd_offset =
+ (addr==0 && dp && dp->d_version==LD_VERSION_SUN) ? PAGSIZ : 0;
+#endif
+ return smp;
+}
+
+/*
+ * Map object identified by link object LOP which was found
+ * in link map LMP.
+ */
+ static struct so_map *
+map_object(sodp, smp)
+ struct sod *sodp;
+ struct so_map *smp;
+{
+ struct _dynamic *dp;
+ char *path, *name = (char *)(sodp->sod_name + LM_LDBASE(smp));
+ int fd;
+ caddr_t addr;
+ struct exec hdr;
+ int usehints = 0;
+ struct so_map *p;
+
+ if (sodp->sod_library) {
+ usehints = 1;
+again:
+ path = rtfindlib(name, sodp->sod_major,
+ sodp->sod_minor, &usehints);
+ if (path == NULL) {
+ errno = ENOENT;
+ return NULL;
+ }
+ } else {
+ if (careful && *name != '/') {
+ errno = EACCES;
+ return NULL;
+ }
+ path = name;
+ }
+
+ /* Check if already loaded */
+ for (p = link_map_head; p; p = p->som_next)
+ if (p->som_path && strcmp(p->som_path, path) == 0)
+ break;
+
+ if (p != NULL)
+ return p;
+
+ if ((fd = open(path, O_RDONLY, 0)) == -1) {
+ if (usehints) {
+ usehints = 0;
+ goto again;
+ }
+ return NULL;
+ }
+
+ if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ (void)close(fd);
+ /*errno = x;*/
+ return NULL;
+ }
+
+ if (N_BADMAG(hdr)) {
+ (void)close(fd);
+ errno = EFTYPE;
+ return NULL;
+ }
+
+ if ((addr = mmap(0, hdr.a_text + hdr.a_data,
+ PROT_READ|PROT_EXEC,
+ MAP_FILE|MAP_COPY, fd, 0)) == (caddr_t)-1) {
+ (void)close(fd);
+ return NULL;
+ }
+
+#if 0
+ if (mmap(addr + hdr.a_text, hdr.a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FILE|MAP_FIXED|MAP_COPY,
+ fd, hdr.a_text) == (caddr_t)-1) {
+ (void)close(fd);
+ return NULL;
+ }
+#endif
+ if (mprotect(addr + hdr.a_text, hdr.a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC) != 0) {
+ (void)close(fd);
+ return NULL;
+ }
+
+ (void)close(fd);
+
+ fd = -1;
+#ifdef NEED_DEV_ZERO
+ if ((fd = open("/dev/zero", O_RDWR, 0)) == -1)
+ warn("open: %s", "/dev/zero");
+#endif
+ if (hdr.a_bss && mmap(addr + hdr.a_text + hdr.a_data, hdr.a_bss,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_ANON|MAP_FIXED|MAP_COPY,
+ fd, hdr.a_text + hdr.a_data) == (caddr_t)-1)
+ return NULL;
+
+#ifdef NEED_DEV_ZERO
+ close(fd);
+#endif
+
+ /* 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;
+
+ return alloc_link_map(path, sodp, smp, addr, dp);
+}
+
+static inline void
+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;
+
+ if (RELOC_EXTERN_P(r))
+ sym = LM_STRINGS(smp) +
+ LM_SYMBOL(smp, RELOC_SYMBOL(r))->nz_strx;
+ else
+ sym = "";
+
+ if (getenv("LD_WARN_NON_PURE_CODE") != NULL)
+ fprintf(stderr,
+ "ld.so: warning: non pure code in %s at %x (%s)\n",
+ 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) {
+
+ err(1, "Cannot enable writes to %s:%s",
+ main_progname, smp->som_path);
+ }
+
+ smp->som_write = 1;
+}
+
+static void
+reloc_map(smp)
+ struct so_map *smp;
+{
+ 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);
+
+ 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 = smp->som_addr + r->r_address;
+
+ check_text_reloc(r, smp, addr);
+
+ if (RELOC_EXTERN_P(r)) {
+ struct so_map *src_map = NULL;
+ struct nzlist *p, *np;
+ long relocation = md_get_addend(r, addr);
+
+ 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;
+
+ np = lookup(sym, &src_map, 0/*XXX-jumpslots!*/);
+ if (np == NULL)
+ errx(1, "Undefined symbol \"%s\" in %s:%s\n",
+ sym, main_progname, smp->som_path);
+
+ /*
+ * 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 += 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) {
+
+ err(1, "Cannot disable writes to %s:%s\n",
+ main_progname, smp->som_path);
+ }
+ smp->som_write = 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_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))();
+}
+
+/*
+ * 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)
+ ;
+
+ /* 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 = LD_BUCKETS(smp->som_dynamic);
+ 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 (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD)
+ continue;
+
+ if (*src_map && smp != *src_map)
+ 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;
+static struct hints_bucket *hbuckets;
+static char *hstrtab;
+
+#define HINTS_VALID (hheader != NULL && hheader != (struct hints_header *)-1)
+
+ static void
+maphints()
+{
+ caddr_t addr;
+ long msize;
+ int fd;
+
+ if ((fd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) {
+ hheader = (struct hints_header *)-1;
+ return;
+ }
+
+ msize = PAGSIZ;
+ addr = mmap(0, msize, PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
+
+ if (addr == (caddr_t)-1) {
+ hheader = (struct hints_header *)-1;
+ return;
+ }
+
+ hheader = (struct hints_header *)addr;
+ if (HH_BADMAG(*hheader)) {
+ munmap(addr, msize);
+ hheader = (struct hints_header *)-1;
+ return;
+ }
+
+ if (hheader->hh_version != LD_HINTS_VERSION_1) {
+ munmap(addr, msize);
+ hheader = (struct hints_header *)-1;
+ return;
+ }
+
+ if (hheader->hh_ehints > msize) {
+ if (mmap(addr+msize, hheader->hh_ehints - msize,
+ PROT_READ, MAP_FILE|MAP_COPY|MAP_FIXED,
+ fd, msize) != (caddr_t)(addr+msize)) {
+
+ munmap((caddr_t)hheader, msize);
+ hheader = (struct hints_header *)-1;
+ return;
+ }
+ }
+ close(fd);
+
+ hbuckets = (struct hints_bucket *)(addr + hheader->hh_hashtab);
+ hstrtab = (char *)(addr + hheader->hh_strtab);
+}
+
+ int
+hinthash(cp, vmajor, vminor)
+ char *cp;
+ int vmajor, vminor;
+{
+ int k = 0;
+
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
+ k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff;
+
+ return k;
+}
+
+#undef major
+#undef minor
+
+ static char *
+findhint(name, major, minor, preferred_path)
+ char *name;
+ int major, minor;
+ char *preferred_path;
+{
+ struct hints_bucket *bp;
+
+ bp = hbuckets + (hinthash(name, major, minor) % hheader->hh_nbucket);
+
+ while (1) {
+ /* Sanity check */
+ if (bp->hi_namex >= hheader->hh_strtab_sz) {
+ fprintf(stderr, "Bad name index: %#x\n", bp->hi_namex);
+ break;
+ }
+ if (bp->hi_pathx >= hheader->hh_strtab_sz) {
+ fprintf(stderr, "Bad path index: %#x\n", bp->hi_pathx);
+ break;
+ }
+
+ if (strcmp(name, hstrtab + bp->hi_namex) == 0) {
+ /* It's `name', check version numbers */
+ if (bp->hi_major == major &&
+ (bp->hi_ndewey < 2 || bp->hi_minor == minor)) {
+ if (preferred_path == NULL ||
+ strcmp(preferred_path,
+ hstrtab + bp->hi_pathx) == 0) {
+ return 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;
+}
+
+ static char *
+rtfindlib(name, major, minor, usehints)
+ char *name;
+ int major, minor;
+ int *usehints;
+{
+ char *hint;
+ char *cp, *ld_path = getenv("LD_LIBRARY_PATH");
+
+ if (hheader == NULL)
+ maphints();
+
+ if (!HINTS_VALID || !(*usehints)) {
+ *usehints = 0;
+ return (char *)findshlib(name, &major, &minor, 0);
+ }
+
+ if (ld_path != NULL) {
+ /* Prefer paths from LD_LIBRARY_PATH */
+ while ((cp = strsep(&ld_path, ":")) != NULL) {
+
+ hint = findhint(name, major, minor, cp);
+ if (ld_path)
+ *(ld_path-1) = ':';
+ if (hint)
+ return hint;
+ }
+ /* Not found in hints, try directory search */
+ hint = (char *)findshlib(name, &major, &minor, 0);
+ if (hint)
+ return hint;
+ }
+
+ /* No LD_LIBRARY_PATH or lib not found in there; check default */
+ hint = findhint(name, major, minor, NULL);
+ if (hint)
+ return hint;
+
+ /* No hints available for name */
+ *usehints = 0;
+ return (char *)findshlib(name, &major, &minor, 0);
+}
+
+static struct somap_private dlmap_private = {
+ 0,
+ (struct so_map *)0,
+ 0,
+#ifdef SUN_COMPAT
+ 0,
+#endif
+};
+
+static struct so_map dlmap = {
+ (caddr_t)0,
+ "internal",
+ (struct so_map *)0,
+ (struct sod *)0,
+ (caddr_t)0,
+ (u_int)0,
+ (struct _dynamic *)0,
+ (caddr_t)&dlmap_private
+};
+static int dlerrno;
+
+ static void *
+__dlopen(name, mode)
+ char *name;
+ int mode;
+{
+ struct sod *sodp;
+ struct so_map *smp;
+
+ /*
+ * A NULL argument returns the current set of mapped objects.
+ */
+ if (name == NULL)
+ return link_map_head;
+
+ if ((sodp = (struct sod *)malloc(sizeof(struct sod))) == NULL) {
+ dlerrno = ENOMEM;
+ return NULL;
+ }
+
+ sodp->sod_name = (long)strdup(name);
+ sodp->sod_library = 0;
+ sodp->sod_major = sodp->sod_minor = 0;
+
+ if ((smp = map_object(sodp, &dlmap)) == NULL) {
+#ifdef DEBUG
+xprintf("%s: %s\n", name, strerror(errno));
+#endif
+ dlerrno = errno;
+ return NULL;
+ }
+ if (LM_PRIVATE(smp)->spd_refcount++ == 0) {
+ LM_PRIVATE(smp)->spd_flags |= RTLD_DL;
+ reloc_map(smp);
+ reloc_copy(smp);
+ init_map(smp, ".init");
+ init_map(smp, "_init");
+ }
+
+ return smp;
+}
+
+ static int
+__dlclose(fd)
+ void *fd;
+{
+ struct so_map *smp = (struct so_map *)fd;
+
+#ifdef DEBUG
+xprintf("dlclose(%s): refcount = %d\n", smp->som_path, LM_PRIVATE(smp)->spd_refcount);
+#endif
+ if (--LM_PRIVATE(smp)->spd_refcount != 0)
+ return 0;
+
+ /* Dismantle shared object map and descriptor */
+ init_map(smp, "_fini");
+#if 0
+ unmap_object(smp);
+ free(smp->som_sod->sod_name);
+ free(smp->som_sod);
+ free(smp);
+#endif
+
+ return 0;
+}
+
+ static void *
+__dlsym(fd, sym)
+ void *fd;
+ char *sym;
+{
+ struct so_map *smp = (struct so_map *)fd, *src_map = NULL;
+ struct nzlist *np;
+ long addr;
+
+ /*
+ * Restrict search to passed map if dlopen()ed.
+ */
+ if (LM_PRIVATE(smp)->spd_flags & RTLD_DL)
+ src_map = smp;
+
+ np = lookup(sym, &src_map, 1);
+ if (np == NULL)
+ return NULL;
+
+ /* Fixup jmpslot so future calls transfer directly to target */
+ addr = np->nz_value;
+ if (src_map)
+ addr += (long)src_map->som_addr;
+
+ return (void *)addr;
+}
+
+ static int
+__dlctl(fd, cmd, arg)
+ void *fd, *arg;
+ int cmd;
+{
+ switch (cmd) {
+ case DL_GETERRNO:
+ *(int *)arg = dlerrno;
+ return 0;
+ default:
+ dlerrno = EOPNOTSUPP;
+ return -1;
+ }
+ return 0;
+}
+
+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..2e8dfe9
--- /dev/null
+++ b/gnu/usr.bin/ld/shlib.c
@@ -0,0 +1,279 @@
+/*
+ * 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.8 1994/02/13 20:41:43 jkh 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", "/usr/X11R6/lib", "/usr/X386/lib", "/usr/local/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.
+ *
+ * MAJOR == -1 && MINOR == -1 --> find highest version
+ * MAJOR != -1 && MINOR == -1 --> find highest minor version
+ * MAJOR == -1 && MINOR != -1 --> invalid
+ * MAJOR != -1 && MINOR != -1 --> find highest micro version
+ */
+
+/* Not interested in devices right now... */
+#undef major
+#undef minor
+
+char *
+findshlib(name, majorp, minorp, do_dot_a)
+char *name;
+int *majorp, *minorp;
+int do_dot_a;
+{
+ int dewey[MAXDEWEY];
+ int ndewey;
+ int tmp[MAXDEWEY];
+ int i;
+ int len;
+ char *lname, *path = NULL;
+ int major = *majorp, minor = *minorp;
+
+ len = strlen(name);
+ lname = (char *)alloca(len + sizeof("lib"));
+ sprintf(lname, "lib%s", name);
+ len += 3;
+
+ ndewey = 0;
+
+ for (i = 0; i < n_search_dirs; i++) {
+ DIR *dd = opendir(search_dirs[i]);
+ struct dirent *dp;
+ int found_dot_a = 0;
+
+ if (dd == NULL)
+ continue;
+
+ while ((dp = readdir(dd)) != NULL) {
+ int n, might_take_it = 0;
+
+ if (do_dot_a && path == NULL &&
+ dp->d_namlen == len + 2 &&
+ strncmp(dp->d_name, lname, len) == 0 &&
+ (dp->d_name+len)[0] == '.' &&
+ (dp->d_name+len)[1] == 'a') {
+
+ path = concat(search_dirs[i], "/", dp->d_name);
+ found_dot_a = 1;
+ }
+
+ if (dp->d_namlen < len + 4)
+ continue;
+ if (strncmp(dp->d_name, lname, len) != 0)
+ continue;
+ if (strncmp(dp->d_name+len, ".so.", 4) != 0)
+ continue;
+
+ if ((n = getdewey(tmp, dp->d_name+len+4)) == 0)
+ continue;
+
+ if (major != -1 && found_dot_a) { /* XXX */
+ free(path);
+ path = NULL;
+ found_dot_a = 0;
+ }
+
+ if (major == -1 && minor == -1) {
+ might_take_it = 1;
+ } else if (major != -1 && minor == -1) {
+ if (tmp[0] == major)
+ might_take_it = 1;
+ } else if (major != -1 && minor != -1) {
+ if (tmp[0] == major)
+ if (n == 1 || tmp[1] >= minor)
+ might_take_it = 1;
+ }
+
+ if (!might_take_it)
+ continue;
+
+ if (cmpndewey(tmp, n, dewey, ndewey) <= 0)
+ continue;
+
+ /* We have a better version */
+ if (path)
+ free(path);
+ path = concat(search_dirs[i], "/", dp->d_name);
+ found_dot_a = 0;
+ bcopy(tmp, dewey, sizeof(dewey));
+ ndewey = n;
+ *majorp = dewey[0];
+ *minorp = dewey[1];
+ }
+ closedir(dd);
+
+ if (found_dot_a)
+ /*
+ * There's a .a archive here.
+ */
+ return path;
+ }
+
+ return path;
+}
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..3545d97
--- /dev/null
+++ b/gnu/usr.bin/ld/sparc/md.h
@@ -0,0 +1,282 @@
+/*
+ * 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.5 1993/12/02 01:03:47 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 CHECK_GOT_RELOC(r) \
+ ((r)->r_type == RELOC_PC10 || (r)->r_type == RELOC_PC22)
+
+#define md_got_reloc(r) (-(r)->r_address)
+
+#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..0d006d0
--- /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.2 1993/11/09 04:19:36 paul 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 rtld's __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's
+ 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..f355b3e
--- /dev/null
+++ b/gnu/usr.bin/ld/symbol.c
@@ -0,0 +1,161 @@
+/*
+ * $Id: symbol.c,v 1.4 1994/02/13 20:41:46 jkh 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_nlist = 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..5e11b0b
--- /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.2 1993/08/01 18:46:59 mycroft 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..6ae1be9
--- /dev/null
+++ b/gnu/usr.bin/ld/warnings.c
@@ -0,0 +1,719 @@
+/*
+ * $Id: warnings.c,v 1.7 1994/06/14 12:45:41 csgr 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"
+
+/*
+ * 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) {
+ if (sp->defined == (N_UNDF|N_EXT))
+ fprintf(outfile, " %s: common, length %#x\n",
+ sp->name, sp->common_size);
+ if (!(sp->flags & GS_REFERENCED))
+ fprintf(outfile, " %s: unreferenced\n", sp->name);
+ else if (sp->so_defined)
+ fprintf(outfile, " %s: sodefined\n", sp->name);
+ else if (!sp->defined)
+ fprintf(outfile, " %s: undefined\n", sp->name);
+ else
+ fprintf(outfile, " %s: %#x, size %#x\n",
+ sp->name, sp->value, sp->size);
+ } 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_warning_symbols; /* List warning syms */
+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
+relocation_entries_relation(rel1, rel2)
+ struct relocation_info *rel1, *rel2;
+{
+ return RELOC_ADDRESS(rel1) - RELOC_ADDRESS(rel2);
+}
+
+/* Moves to the next debugging symbol in the file. USE_DATA_SYMBOLS
+ determines the type of the debugging symbol to look for (DSLINE or
+ SLINE). STATE_POINTER keeps track of the old and new locatiosn in
+ the file. It assumes that state_pointer[1] is valid; ie
+ that it.sym points into some entry in the symbol table. If
+ state_pointer[1].sym == 0, this routine should not be called. */
+
+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 *endp = entry->symbols + entry->nsymbols;
+
+
+ current->sym = next->sym;
+ current->line = next->line;
+ current->filename = next->filename;
+
+ while (++(next->sym) < endp) {
+
+ 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;
+{
+ struct localsymbol *lsp;
+ struct line_debug_entry *state_pointer = (struct line_debug_entry *)
+ xmalloc(3 * sizeof(struct line_debug_entry));
+
+ register struct line_debug_entry
+ *current = state_pointer,
+ *next = state_pointer + 1,
+ *source = state_pointer + 2; /* Used to store source file */
+
+
+ for (lsp = entry->symbols; lsp < entry->symbols+entry->nsymbols; lsp++)
+ if (lsp->nzlist.nlist.n_type == N_SO)
+ break;
+
+ if (lsp >= entry->symbols + entry->nsymbols) {
+ /* 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 *reloc, *reloc_start =
+ data_segment ? entry->datarel : entry->textrel;
+
+ int reloc_size = (data_segment ? entry->ndatarel : entry->ntextrel);
+ int start_of_segment = (data_segment ?
+ entry->data_start_address :
+ entry->text_start_address);
+ struct localsymbol *start_of_syms = entry->symbols;
+ struct line_debug_entry *state_pointer =
+ init_debug_scan(data_segment != 0, entry);
+
+ register struct line_debug_entry *current = state_pointer;
+
+ /* Assigned to generally static values; should not be written into. */
+ char *errfmt;
+
+ /*
+ * Assigned to alloca'd values cand copied into; should be freed when
+ * done.
+ */
+ char *errmsg;
+ int invalidate_line_number;
+
+ /*
+ * We need to sort the relocation info here. Sheesh, so much effort
+ * for one lousy error optimization.
+ */
+
+ qsort(reloc_start, reloc_size, sizeof(struct relocation_info),
+ relocation_entries_relation);
+
+ for (reloc = reloc_start;
+ reloc < (reloc_start + reloc_size);
+ reloc++) {
+ register struct localsymbol *lsp;
+ register symbol *g;
+
+ /*
+ * If the relocation isn't resolved through a symbol,
+ * continue
+ */
+ if (!RELOC_EXTERN_P(reloc))
+ continue;
+
+ lsp = &entry->symbols[RELOC_SYMBOL(reloc)];
+
+ /*
+ * Local symbols shouldn't ever be used by relocation info,
+ * so the next should be safe. This is, of course, wrong.
+ * References to local BSS symbols can be the targets of
+ * relocation info, and they can (must) be resolved through
+ * symbols. However, these must be defined properly, (the
+ * assembler would have caught it otherwise), so we can
+ * ignore these cases.
+ */
+
+ if ((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 >= MAX_UREFS_PRINTED)
+ /* Listed too many */
+ continue;
+
+ /* Undefined symbol which we should mention */
+
+ if (++(g->undef_refs) == MAX_UREFS_PRINTED) {
+ errfmt = "More undefined symbol %s refs follow";
+ invalidate_line_number = 1;
+ } else {
+ errfmt =
+ "Undefined symbol `%s' referenced from %s segment";
+ invalidate_line_number = 0;
+ }
+ } else { /* Defined */
+ /* Potential symbol warning here */
+ if (!g->warning)
+ continue;
+
+ /* Mark as being noted by relocation warning pass. */
+ SET_BIT(nlist_bitvector, 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(reloc) + start_of_segment,
+ state_pointer);
+
+ if (current->line >= 0)
+ fprintf(outfile, "%s:%d: %s\n", current->filename,
+ invalidate_line_number ? 0 : current->line, errmsg);
+ else
+ fprintf(outfile, "%s: %s\n", current->filename, errmsg);
+
+ if (errfmt != 0)
+ free(errmsg);
+ }
+
+ free(state_pointer);
+}
+
+/*
+ * Print on OUTFILE a list of all warnings generated by references and/or
+ * definitions in the file ENTRY. List source file and line number if
+ * possible, just the .o file if not.
+ */
+
+void
+do_file_warnings (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ int number_of_syms = entry->nsymbols;
+ unsigned char *nlist_bitvector = (unsigned char *)
+ alloca ((number_of_syms >> 3) + 1);
+ struct line_debug_entry *text_scan, *data_scan;
+ int i;
+ char *errfmt, *file_name;
+ int line_number;
+ int dont_allow_symbol_name;
+
+ bzero (nlist_bitvector, (number_of_syms >> 3) + 1);
+
+ /* Read in the files strings if they aren't available */
+ if (!entry->strings) {
+ int desc;
+
+ entry->strings = (char *)alloca(entry->string_size);
+ desc = file_open(entry);
+ read_entry_strings(desc, entry);
+ }
+
+ 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 < number_of_syms; i++) {
+ struct nlist *s;
+ symbol *g;
+
+ g = entry->symbols[i].symbol;
+ s = &entry->symbols[i].nzlist.nlist;
+
+ /*
+ * XXX This is a temporary fence to correct an
+ * incorrect assumption made in the case of symbols
+ * which do not have entries in the (global)
+ * symbol table.
+ */
+ if(g == NULL)
+ continue;
+
+ if (g == NULL)
+ continue;
+
+ if (!(s->n_type & N_EXT) && !SET_ELEMENT_P(s->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 (s->n_type) {
+
+ case N_TEXT | N_EXT:
+ line_number =
+ address_to_line(s->n_value, text_scan);
+ file_name = text_scan[0].filename;
+ break;
+
+ case N_DATA | N_EXT:
+ line_number =
+ address_to_line(s->n_value, data_scan);
+ file_name = data_scan[0].filename;
+ break;
+
+ case N_SETA | N_EXT:
+ case N_SETT | N_EXT:
+ case N_SETD | N_EXT:
+ case N_SETB | N_EXT:
+ if (g->mult_defs == 2)
+ continue;
+ errfmt =
+ "First set element definition of symbol %s (multiply defined)";
+ line_number = -1;
+ break;
+
+ default:
+printf("multiply defined: %s, type %#x\n", g->name, s->n_type);
+ /* Don't print out multiple defs at references.*/
+ continue;
+ }
+
+ } else if (BIT_SET_P(nlist_bitvector, i)) {
+ continue;
+ } else if (list_unresolved_refs &&
+ !g->defined && !g->so_defined) {
+
+ if (g->undef_refs >= MAX_UREFS_PRINTED)
+ continue;
+
+ if (++(g->undef_refs) == MAX_UREFS_PRINTED)
+ errfmt = "More undefined \"%s\" refs follow";
+ else
+ errfmt = "Undefined symbol \"%s\" referenced";
+ line_number = -1;
+ } else if (g->warning) {
+ /*
+ * There are two cases in which we don't want to do
+ * this. The first is if this is a definition instead
+ * do a reference. The second is if it's the reference
+ * used by the warning stabs itself.
+ */
+ if (s->n_type != (N_EXT | N_UNDF) ||
+ (i && (s-1)->n_type == N_WARNING))
+ continue;
+
+ errfmt = g->warning;
+ line_number = -1;
+ dont_allow_symbol_name = 1;
+ } else
+ continue;
+
+ if (line_number == -1)
+ fprintf(outfile, "%s: ", entry->filename);
+ else
+ fprintf(outfile, "%s:%d: ", file_name, line_number);
+
+ if (dont_allow_symbol_name)
+ fprintf(outfile, "%s", errfmt);
+ else
+ fprintf(outfile, errfmt, g->name);
+
+ fputc('\n', outfile);
+ }
+ free(text_scan);
+ free(data_scan);
+ entry->strings = 0; /* Since it will dissapear anyway. */
+}
+
+int
+do_warnings(outfile)
+ FILE *outfile;
+{
+ list_unresolved_refs = !relocatable_output &&
+ (undefined_global_sym_count || undefined_shobj_sym_count);
+ list_warning_symbols = warning_count;
+ list_multiple_defs = multiple_def_count != 0;
+
+ if (!(list_unresolved_refs ||
+ list_warning_symbols || list_multiple_defs))
+ /* No need to run this routine */
+ return 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 || 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..0e7e506
--- /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..b993e79
--- /dev/null
+++ b/gnu/usr.bin/man/Makefile.inc
@@ -0,0 +1,36 @@
+#
+# 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 -cs
+manpath_config_file= /etc/manpath.config
+troff= /usr/bin/groff -Tps -man
+nroff= /usr/bin/groff -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
+
+# For scripts.
+.if !target(obj)
+obj:
+ @cd ${.CURDIR}; rm -rf obj; \
+ here=`pwd`; dest=/usr/obj/`echo $$here | sed 's,/usr/src/,,'`; \
+ echo "$$here -> $$dest"; ln -s $$dest obj; \
+ if test -d /usr/obj -a ! -d $$dest; then \
+ mkdir -p $$dest; \
+ else \
+ true; \
+ fi;
+.endif
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..f353eb7
--- /dev/null
+++ b/gnu/usr.bin/man/apropos/Makefile
@@ -0,0 +1,47 @@
+# $Id$
+
+.if exists(${.CURDIR}/obj)
+MAN1= ${.CURDIR}/obj/apropos.1
+TARG= ${.CURDIR}/obj/apropos
+.else
+MAN1= ${.CURDIR}/apropos.1
+TARG= ${.CURDIR}/apropos
+.endif
+
+MANDEPEND= ${MAN1}
+
+all: ${TARG} ${MAN1}
+
+depend rcsfreeze tags all:
+ @echo -n
+
+cleandir: clean
+ cd ${.CURDIR}; rm -rf obj;
+
+clean:
+ @rm -f ${TARG} ${MAN1}
+
+${TARG}: ${.CURDIR}/apropos.sh
+ sed -e 's,%libdir%,${libdir},' -e 's,%bindir%,${bindir},' \
+ -e 's,%pager%,${pager},' \
+ ${.CURDIR}/apropos.sh > $@
+
+${MAN1}: ${.CURDIR}/apropos.man
+ 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}/apropos.man > $@
+
+install: ${TARG} maninstall
+ install -c -o bin -g bin -m 555 ${TARG} ${DESTDIR}/usr/bin
+
+
+.include "../Makefile.inc"
+
+.if make(maninstall) || make(install)
+.if !defined(NOMAN)
+.include <bsd.man.mk>
+.elif !target(maninstall)
+maninstall:
+.endif
+.endif
diff --git a/gnu/usr.bin/man/apropos/apropos b/gnu/usr.bin/man/apropos/apropos
new file mode 100644
index 0000000..8735e5f
--- /dev/null
+++ b/gnu/usr.bin/man/apropos/apropos
@@ -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=/etc
+
+if [ $# = 0 ]
+then
+ echo "usage: `basename $0` keyword ..."
+ exit 1
+fi
+
+manpath=`/usr/bin/manpath -q | tr : '\040'`
+
+if [ "$manpath" = "" ]
+then
+ echo "whatis: manpath is null"
+ exit 1
+fi
+
+if [ "$PAGER" = "" ]
+then
+ PAGER="/usr/gnu/bin/less -sC"
+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/apropos/apropos.1 b/gnu/usr.bin/man/apropos/apropos.1
new file mode 100644
index 0000000..3bb3e17
--- /dev/null
+++ b/gnu/usr.bin/man/apropos/apropos.1
@@ -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.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..f4bd03f
--- /dev/null
+++ b/gnu/usr.bin/man/catman/Makefile
@@ -0,0 +1,15 @@
+NOMAN= noman
+CLEANFILES= catman
+
+beforeinstall: catman
+ install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ catman ${DESTDIR}${BINDIR}
+
+.include <bsd.prog.mk>
+
+catman: catman.sh
+ sed -e 's,%compress%,${compress},' \
+ -e 's,%compext%,${compext},' \
+ -e 's,%zcat%,${zcat},' \
+ ${.CURDIR}/catman.sh > catman
+
diff --git a/gnu/usr.bin/man/catman/catman b/gnu/usr.bin/man/catman/catman
new file mode 100644
index 0000000..a2d16a1
--- /dev/null
+++ b/gnu/usr.bin/man/catman/catman
@@ -0,0 +1,36 @@
+#!/bin/sh
+# usage: sh catman
+# put the section numbers here:
+SECTIONS="1 2 3 4 5 6 7 8"
+MANDIR=/usr/share/man
+
+formatman()
+{
+ echo " "$1 "->" $*
+ (cd cat$section; rm -f $*)
+ nroff -man < man$section/$1 > cat$section/$1
+ catfile=$1; shift
+ while [ $# -gt 0 ]
+ do
+ ln cat$section/$catfile cat$section/$1
+ shift
+ done
+}
+
+cd $MANDIR
+for section in $SECTIONS
+do
+ echo formatting section $section ...
+
+ IFS=" "
+ allfiles=`ls -i1 man$section | sort | awk '{if (inode ~ $1) printf "/" $2;
+ else printf " " $2; inode = $1 } END {printf "\n"}'`
+ for files in $allfiles
+ do
+ IFS="/"
+ tfiles=`echo $files`
+ IFS=" "
+ formatman $tfiles
+ done
+done
+exit 0
diff --git a/gnu/usr.bin/man/catman/catman.sh b/gnu/usr.bin/man/catman/catman.sh
new file mode 100644
index 0000000..456cb57
--- /dev/null
+++ b/gnu/usr.bin/man/catman/catman.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# usage: sh catman
+# put the section numbers here:
+SECTIONS="1 2 3 4 5 6 7 8"
+MANDIR=/usr/share/man
+
+formatman()
+{
+ suffix=`echo $1 | sed -e 's/.*\\.//'`
+ (cd cat$section; rm -f $*)
+ if [ ".$suffix" = "%compext%" ]; then
+ adds=
+ %zcat% man$section/$1 | nroff -man | %compress% > cat$section/$1$adds
+ else
+ adds=%compext%
+ nroff -man < man$section/$1 | %compress% > cat$section/$1$adds
+ fi
+ echo " "$* "->" $1$adds
+ catfile=$1$adds; shift
+ while [ $# -gt 0 ]
+ do
+ ln cat$section/$catfile cat$section/$1$adds
+ shift
+ done
+}
+
+cd $MANDIR
+for section in $SECTIONS
+do
+ echo formatting section $section ...
+
+ IFS=" "
+ allfiles=`ls -i1 man$section | sort | awk '{if (inode ~ $1) printf "/" $2;
+ else printf " " $2; inode = $1 } END {printf "\n"}'`
+ for files in $allfiles
+ do
+ IFS="/"
+ tfiles=`echo $files`
+ IFS=" "
+ formatman $tfiles
+ done
+done
+exit 0
diff --git a/gnu/usr.bin/man/lib/Makefile b/gnu/usr.bin/man/lib/Makefile
new file mode 100644
index 0000000..7134c86
--- /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
+
+libman.a:: ${CONFH}
+
+install:
+ @echo -n
+
+depend ${CONFH}: ${.CURDIR}/config.h_dist ../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 b/gnu/usr.bin/man/lib/config.h
new file mode 100644
index 0000000..2c23168
--- /dev/null
+++ b/gnu/usr.bin/man/lib/config.h
@@ -0,0 +1,216 @@
+/*
+ * 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
+ */
+
+#ifdef COMPRESS
+#define DO_COMPRESS
+#define DO_UNCOMPRESS
+#endif
+
+/*
+ * 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 "/usr/bin/apropos"
+#endif
+
+#ifndef WHATIS
+#define WHATIS "/usr/bin/whatis"
+#endif
+
+#ifndef PAGER
+#define PAGER "/usr/gnu/bin/less -sC"
+#endif
+
+#ifdef HAS_TROFF
+#ifndef TROFF
+#define TROFF "/usr/bin/groff -Tps -man"
+#endif
+#endif
+
+#ifndef NROFF
+#define NROFF "/usr/bin/groff -Tascii -man"
+#endif
+
+#ifndef EQN
+#define EQN "/usr/bin/eqn -Tps"
+#endif
+
+#ifndef NEQN
+#define NEQN "/usr/bin/eqn -Tascii"
+#endif
+
+#ifndef TBL
+#define TBL "/usr/bin/tbl"
+#endif
+
+#ifndef COL
+#define COL "/usr/bin/col"
+#endif
+
+#ifndef VGRIND
+#define VGRIND "/usr/bin/vgrind"
+#endif
+
+#ifndef REFER
+#define REFER "/usr/bin/refer"
+#endif
+
+#ifndef GRAP
+#define GRAP ""
+#endif
+
+#ifndef PIC
+#define PIC "/usr/bin/pic"
+#endif
+
+/*
+ * Define the absolute path to the configuration file.
+ */
+#ifndef MAN_MAIN
+ static char config_file[] = "/etc/manpath.config";
+#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.
+ */
+#ifdef DO_UNCOMPRESS
+/* .F files */
+#define FCAT ""
+/* .Y files */
+#define YCAT ""
+/* .Z files */
+#define ZCAT "/usr/bin/zcat"
+#endif
+
+/*
+ * 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.
+ */
+#ifdef DO_COMPRESS
+#define COMPRESSOR ""
+#define COMPRESS_EXT ""
+#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", "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/config.h_dist b/gnu/usr.bin/man/lib/config.h_dist
new file mode 100644
index 0000000..3438e6f
--- /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", "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..76f8e70
--- /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..e3be4a0
--- /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..e8253a8
--- /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 0;
+ 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..bd14975
--- /dev/null
+++ b/gnu/usr.bin/man/makewhatis/Makefile
@@ -0,0 +1,17 @@
+# @(#)Makefile 5.6 (Berkeley) 6/23/90
+
+NOMAN= noman
+CLEANFILES= makewhatis
+
+beforeinstall: makewhatis
+ install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ makewhatis ${DESTDIR}${BINDIR}
+
+.include <bsd.prog.mk>
+
+makewhatis: makewhatis.sh
+ sed -e 's/%sections%/ "1", "n", "l", "6", "8", "2", "3", "4", "5", "7", "p", "o", NULL/' \
+ -e 's,%zcat%,${zcat},' \
+ -e 's,%compext%,${compext},' \
+ ${.CURDIR}/makewhatis.sh > makewhatis
+
diff --git a/gnu/usr.bin/man/makewhatis/makewhatis b/gnu/usr.bin/man/makewhatis/makewhatis
new file mode 100644
index 0000000..e6c238c
--- /dev/null
+++ b/gnu/usr.bin/man/makewhatis/makewhatis
@@ -0,0 +1,79 @@
+#!/bin/sh
+#
+# makewhatis -- update the whatis database in the man directories.
+#
+# 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=/bin:/usr/local/bin:/usr/ucb:/usr/bin
+
+if [ $# = 0 ]
+then
+ echo "usage: makewhatis directory [...]"
+ exit 1
+fi
+
+for dir in $*
+do
+ cd $dir
+ for subdir in man*
+ do
+ if [ -d $subdir ]
+ then
+ for f in `find . -name '*' -print`
+ do
+ sed -n '/^\.TH.*$/p
+ /^\.SH[ ]*NAME/,/^\.SH/p' $f |\
+ sed -e 's/\\[ ]*\-/-/
+ s/^.PP.*$//
+ s/\\(em//
+ s/\\fI//
+ s/\\fR//' |\
+ awk 'BEGIN {insh = 0} {
+ if ($1 == ".TH")
+ sect = $3
+ else if ($1 == ".SH" && insh == 1) {
+ if (i > 0 && name != NULL) {
+ namesect = sprintf("%s (%s)", name, sect)
+ printf("%-20.20s", namesect)
+ printf(" - ")
+ for (j = 0; j < i-1; j++)
+ printf("%s ", desc[j])
+ printf("%s\n", desc[i-1])
+ }
+ } else if ($1 == ".SH" && insh == 0) {
+ insh = 1
+ count = 0
+ i = 0
+ } else if (insh == 1) {
+ count++
+ if (count == 1 && NF > 2) {
+ start = 2
+ if ($2 == "-") start = 3
+ if (NF > start + 1)
+ for (j = start; j <= NF; j++)
+ desc[i++] = $j
+ name = $1
+ } else {
+ for (j = 1; j <= NF; j++)
+ desc[i++] = $j
+ }
+ }
+ }'
+ done
+ cd ..
+ fi
+ done | sort | colrm 80 > $dir/whatis.db.tmp
+ mv $dir/whatis.db.tmp $dir/whatis
+done
+
+exit
diff --git a/gnu/usr.bin/man/makewhatis/makewhatis.sh b/gnu/usr.bin/man/makewhatis/makewhatis.sh
new file mode 100644
index 0000000..28b871d
--- /dev/null
+++ b/gnu/usr.bin/man/makewhatis/makewhatis.sh
@@ -0,0 +1,120 @@
+#!/bin/sh
+#
+# makewhatis -- update the whatis database in the man directories.
+#
+# 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=/bin:/usr/local/bin:/usr/ucb:/usr/bin
+
+if [ $# = 0 ]
+then
+ echo "usage: makewhatis directory [...]"
+ exit 1
+fi
+for dir in $*
+do
+ cd $dir
+ for subdir in man*
+ do
+ if [ -d $subdir ]
+ then
+ for f in `find $subdir -type f -print`
+ do
+ suffix=`echo $f | sed -e 's/.*\\.//'`
+ if [ ".$suffix" = "%compext%" ]; then
+ output=%zcat%
+ else
+ output=cat
+ fi
+ $output $f | \
+ sed -n '/^\.TH.*$/p
+ /^\.Dt.*$/p
+ /^\.S[hH][ ]*NAME/,/^\.S[hH]/p'|\
+ sed -e 's/\\[ ]*\-/-/
+ s/^.P[Pp].*$//
+ s/\\(em//
+ s/\\fI//
+ s/\\fR//' |\
+ awk 'BEGIN {insh = 0; inSh = 0; Nd = 0} {
+ if ($1 == ".TH" || $1 == ".Dt")
+ sect = $3
+ else if (($1 == ".br" && insh == 1)\
+ || ($1 == ".SH" && insh == 1)\
+ || ($1 == ".Sh" && inSh == 1)) {
+ if (i > 0 && nc > 0) {
+ for (k= 1; k <= nc; k++) {
+ namesect = sprintf("%s (%s)", name[k], sect)
+ printf("%s", namesect)
+ printf(" - ")
+ for (j = 0; j < i-1; j++)
+ printf("%s ", desc[j])
+ printf("%s\n", desc[i-1])
+ }
+ }
+ count = 0
+ i = 0
+ nc = 0
+ } else if ($1 == ".SH" && insh == 0) {
+ insh = 1
+ count = 0
+ i = 0
+ nc = 0
+ } else if ($1 == ".Sh" && inSh == 0) {
+ inSh = 1
+ i = 0
+ nc = 0
+ } else if (insh == 1) {
+ count++
+ if (count == 1 && NF > 2) {
+ start = 2
+ for (k = 1; k <= NF; k++)
+ if ($k == "-") {
+ start = k + 1
+ break
+ } else {
+ sub(",","",$k)
+ if ($k != "")
+ name[++nc] = $k
+ }
+ if (NF >= start)
+ for (j = start; j <= NF; j++)
+ desc[i++] = $j
+ } else {
+ for (j = 1; j <= NF; j++)
+ desc[i++] = $j
+ }
+ } else if ($1 == ".Nm" && inSh == 1 && Nd == 0) {
+ for (k = 2; k <= NF; k++) {
+ sub(",","",$k)
+ if ($k != "")
+ name[++nc] = $k
+ }
+ } else if ($1 == ".Nd" && inSh == 1) {
+ Nd = 1
+ for (j = 2; j <= NF; j++)
+ desc[i++] = $j
+ } else if (Nd == 1) {
+ start = 1
+ if ($1 ~ /\..*/)
+ start = 2
+ for (j = start; j <= NF; j++)
+ desc[i++] = $j
+ }
+ }'
+ done
+ fi
+ done | sort | colrm 80 | uniq > $dir/whatis.db.tmp
+ mv $dir/whatis.db.tmp $dir/whatis
+done
+
+exit
diff --git a/gnu/usr.bin/man/man/Makefile b/gnu/usr.bin/man/man/Makefile
new file mode 100644
index 0000000..aaeb086
--- /dev/null
+++ b/gnu/usr.bin/man/man/Makefile
@@ -0,0 +1,31 @@
+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}
+
+${MAN1}: ${.CURDIR}/man.man
+ 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..5bfb1bf
--- /dev/null
+++ b/gnu/usr.bin/man/man/glob.c
@@ -0,0 +1,680 @@
+/* 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;
+
+ 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')
+ return 0; /* Missing ']'. */
+
+ 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;
+ 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.1 b/gnu/usr.bin/man/man/man.1
new file mode 100644
index 0000000..f17aced
--- /dev/null
+++ b/gnu/usr.bin/man/man/man.1
@@ -0,0 +1,132 @@
+.\" 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.
+.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 /usr/local/bin/less -sC,
+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 /usr/bin/groff -Tps -man
+to format the manual page, passing the output to
+.B stdout.
+The output from
+.B /usr/bin/groff -Tps -man
+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 /usr/local/bin/less -sC
+is used.
+.SH "SEE ALSO"
+apropos(1), whatis(1), manpath(1), less(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/man.c b/gnu/usr.bin/man/man/man.c
new file mode 100644
index 0000000..262e333
--- /dev/null
+++ b/gnu/usr.bin/man/man/man.c
@@ -0,0 +1,1430 @@
+/*
+ * 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;
+}
+
+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)
+ {
+ fprintf (stderr, "Warning: couldn't stat file %s!\n", p);
+ }
+ else if (status == 0)
+ {
+ 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])))
+ 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) {
+ 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..bddfc02
--- /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), less(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..ccf7a55
--- /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..a61761f
--- /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..4d9eb63
--- /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..6b6bfbb
--- /dev/null
+++ b/gnu/usr.bin/man/manpath/Makefile
@@ -0,0 +1,30 @@
+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}
+
+${MAN1}: ${.CURDIR}/manpath.man
+ 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 555 ${.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..ccf7a55
--- /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..677b1ad
--- /dev/null
+++ b/gnu/usr.bin/man/manpath/manpath.config
@@ -0,0 +1,32 @@
+# 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
+MANDATORY_MANPATH /usr/gnu/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/gnu /usr/gnu/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..a61761f
--- /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..b3cd6a8
--- /dev/null
+++ b/gnu/usr.bin/man/whatis/Makefile
@@ -0,0 +1,44 @@
+.if exists(${.CURDIR}/obj)
+MAN1= ${.CURDIR}/obj/whatis.1
+TARG= ${.CURDIR}/obj/whatis
+.else
+MAN1= ${.CURDIR}/whatis.1
+TARG= ${.CURDIR}/whatis
+.endif
+
+MANDEPEND= ${MAN1}
+
+all: ${TARG} ${MAN1}
+
+depend rcsfreeze tags all:
+ @echo -n
+
+cleandir: clean
+ cd ${.CURDIR}; rm -rf obj;
+
+clean:
+ @rm -f ${TARG} ${MAN1}
+
+${TARG}: ${.CURDIR}/whatis.sh
+ sed -e 's,%libdir%,${libdir},' -e 's,%bindir%,${bindir},' \
+ -e 's,%pager%,${pager},' \
+ ${.CURDIR}/whatis.sh > ${TARG}
+
+${MAN1}: ${.CURDIR}/whatis.man
+ 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}/whatis.man > ${MAN1}
+
+install: ${TARG} maninstall
+ install -c -o bin -g bin -m 555 ${TARG} ${DESTDIR}/usr/bin
+
+
+.include "../Makefile.inc"
+.if make(maninstall) || make(install)
+.if !defined(NOMAN)
+.include <bsd.man.mk>
+.else
+maninstall:
+.endif
+.endif
diff --git a/gnu/usr.bin/man/whatis/whatis b/gnu/usr.bin/man/whatis/whatis
new file mode 100644
index 0000000..e8cae0a
--- /dev/null
+++ b/gnu/usr.bin/man/whatis/whatis
@@ -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=/etc
+
+if [ $# = 0 ]
+then
+ echo "usage: `basename $0` name ..."
+ exit 1
+fi
+
+manpath=`/usr/bin/manpath -q | tr : '\040'`
+
+if [ "$manpath" = "" ]
+then
+ echo "whatis: manpath is null"
+ exit 1
+fi
+
+if [ "$PAGER" = "" ]
+then
+ PAGER="/usr/gnu/bin/less -sC"
+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/man/whatis/whatis.1 b/gnu/usr.bin/man/whatis/whatis.1
new file mode 100644
index 0000000..9e5528d
--- /dev/null
+++ b/gnu/usr.bin/man/whatis/whatis.1
@@ -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.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/patch/EXTERN.h b/gnu/usr.bin/patch/EXTERN.h
new file mode 100644
index 0000000..bdc1ef9
--- /dev/null
+++ b/gnu/usr.bin/patch/EXTERN.h
@@ -0,0 +1,21 @@
+/* $Header: EXTERN.h,v 2.0 86/09/17 15:35:37 lwall Exp $
+ *
+ * $Log: EXTERN.h,v $
+ * Revision 2.0 86/09/17 15:35:37 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#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..38574ef
--- /dev/null
+++ b/gnu/usr.bin/patch/INTERN.h
@@ -0,0 +1,19 @@
+/* $Header: INTERN.h,v 2.0 86/09/17 15:35:58 lwall Exp $
+ *
+ * $Log: INTERN.h,v $
+ * Revision 2.0 86/09/17 15:35:58 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#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..d614e89
--- /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..d7eb5874
--- /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..9bae5bd
--- /dev/null
+++ b/gnu/usr.bin/patch/common.h
@@ -0,0 +1,193 @@
+/* $Header: /a/cvs/386BSD/src/gnu/patch/common.h,v 1.1.1.1 1993/06/19 14:21:52 paul Exp $
+ *
+ * $Log: common.h,v $
+ * 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..71623d7
--- /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..c99054f
--- /dev/null
+++ b/gnu/usr.bin/patch/inp.c
@@ -0,0 +1,369 @@
+/* $Header: inp.c,v 2.0.1.1 88/06/03 15:06:13 lwall Locked $
+ *
+ * $Log: inp.c,v $
+ * 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);
+
+ statfailed = stat(filename, &filestat);
+ if (statfailed && ok_to_create_file) {
+ if (verbose)
+ say2("(Creating file %s...)\n",filename);
+ makedirs(filename, TRUE);
+ close(creat(filename, 0666));
+ statfailed = stat(filename, &filestat);
+ }
+ /* 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..c6d2a91
--- /dev/null
+++ b/gnu/usr.bin/patch/inp.h
@@ -0,0 +1,18 @@
+/* $Header: inp.h,v 2.0 86/09/17 15:37:25 lwall Exp $
+ *
+ * $Log: inp.h,v $
+ * Revision 2.0 86/09/17 15:37:25 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+EXT LINENUM input_lines INIT(0); /* how long is input file in lines */
+EXT LINENUM last_frozen_line INIT(0); /* how many input lines have been */
+ /* irretractibly output */
+
+bool rev_in_string();
+void scan_input();
+bool plan_a(); /* returns false if insufficient memory */
+void plan_b();
+char *ifetch();
+
diff --git a/gnu/usr.bin/patch/patch.1 b/gnu/usr.bin/patch/patch.1
new file mode 100644
index 0000000..6af062a
--- /dev/null
+++ b/gnu/usr.bin/patch/patch.1
@@ -0,0 +1,584 @@
+.\" -*- nroff -*-
+.rn '' }`
+'\" $Header: /home/cvs/386BSD/src/gnu/usr.bin/patch/patch.1,v 1.3 1994/02/17 22:20:33 jkh Exp $
+'\"
+'\" $Log: patch.1,v $
+.\" 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 context diff header takes precedence over an Index line.
+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..626c453
--- /dev/null
+++ b/gnu/usr.bin/patch/patch.c
@@ -0,0 +1,967 @@
+char rcsid[] =
+ "$Header: /home/cvs/386BSD/src/gnu/usr.bin/patch/patch.c,v 1.3 1994/02/17 22:20:34 jkh 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.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. */
+static 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..0a844f2
--- /dev/null
+++ b/gnu/usr.bin/patch/pch.c
@@ -0,0 +1,1317 @@
+/* $Header: /home/cvs/386BSD/src/gnu/usr.bin/patch/pch.c,v 1.3 1994/02/17 22:20:36 jkh Exp $
+ *
+ * $Log: pch.c,v $
+ * 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 (oldname)
+ filearg[0] = savestr(oldname);
+ else if (newname)
+ filearg[0] = savestr(newname);
+ else if (indname)
+ filearg[0] = savestr(indname);
+ }
+ if (bestguess) {
+ free(bestguess);
+ bestguess = Nullch;
+ }
+ if (filearg[0] != Nullch)
+ bestguess = savestr(filearg[0]);
+ else if (indtmp != Nullch)
+ bestguess = fetchname(indtmp, strippath, TRUE);
+ else {
+ if (oldtmp != Nullch)
+ oldname = fetchname(oldtmp, strippath, TRUE);
+ if (newtmp != Nullch)
+ newname = fetchname(newtmp, strippath, TRUE);
+ if (oldname && newname) {
+ if (strlen(oldname) < strlen(newname))
+ bestguess = savestr(oldname);
+ else
+ bestguess = savestr(newname);
+ }
+ else if (oldname)
+ bestguess = savestr(oldname);
+ else if (newname)
+ bestguess = savestr(newname);
+ }
+ if (indtmp != Nullch)
+ free(indtmp);
+ if (oldtmp != Nullch)
+ free(oldtmp);
+ if (newtmp != Nullch)
+ free(newtmp);
+ if (indname != Nullch)
+ free(indname);
+ if (oldname != Nullch)
+ free(oldname);
+ if (newname != Nullch)
+ free(newname);
+ return retval;
+}
+
+/* Remember where this patch ends so we know where to start up again. */
+
+void
+next_intuit_at(file_pos,file_line)
+long file_pos;
+long file_line;
+{
+ p_base = file_pos;
+ p_bline = file_line;
+}
+
+/* Basically a verbose fseek() to the actual diff listing. */
+
+void
+skip_to(file_pos,file_line)
+long file_pos;
+long file_line;
+{
+ char *ret;
+
+ assert(p_base <= file_pos);
+ if (verbose && p_base < file_pos) {
+ Fseek(pfp, p_base, 0);
+ say1("The text leading up to this was:\n--------------------------\n");
+ while (ftell(pfp) < file_pos) {
+ ret = fgets(buf, sizeof buf, pfp);
+ assert(ret != Nullch);
+ say2("|%s", buf);
+ }
+ say1("--------------------------\n");
+ }
+ else
+ Fseek(pfp, file_pos, 0);
+ p_input_line = file_line - 1;
+}
+
+/* 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..97a5b28
--- /dev/null
+++ b/gnu/usr.bin/patch/pch.h
@@ -0,0 +1,36 @@
+/* $Header: pch.h,v 2.0.1.1 87/01/30 22:47:16 lwall Exp $
+ *
+ * $Log: pch.h,v $
+ * Revision 2.0.1.1 87/01/30 22:47:16 lwall
+ * Added do_ed_script().
+ *
+ * Revision 2.0 86/09/17 15:39:57 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+EXT FILE *pfp INIT(Nullfp); /* patch file pointer */
+
+void re_patch();
+void open_patch_file();
+void set_hunkmax();
+void grow_hunkmax();
+bool there_is_another_patch();
+int intuit_diff_type();
+void next_intuit_at();
+void skip_to();
+bool another_hunk();
+bool pch_swap();
+char *pfetch();
+short pch_line_len();
+LINENUM pch_first();
+LINENUM pch_ptrn_lines();
+LINENUM pch_newfirst();
+LINENUM pch_repl_lines();
+LINENUM pch_end();
+LINENUM pch_context();
+LINENUM pch_hunk_beg();
+char pch_char();
+char *pfetch();
+char *pgets();
+void do_ed_script();
diff --git a/gnu/usr.bin/patch/util.c b/gnu/usr.bin/patch/util.c
new file mode 100644
index 0000000..ecb85ff
--- /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..d8e46bb
--- /dev/null
+++ b/gnu/usr.bin/patch/util.h
@@ -0,0 +1,88 @@
+/* $Header: util.h,v 2.0 86/09/17 15:40:06 lwall Exp $
+ *
+ * $Log: util.h,v $
+ * Revision 2.0 86/09/17 15:40:06 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+/* and for those machine that can't handle a variable argument list */
+
+#ifdef CANVARARG
+
+#define say1 say
+#define say2 say
+#define say3 say
+#define say4 say
+#define ask1 ask
+#define ask2 ask
+#define ask3 ask
+#define ask4 ask
+#define fatal1 fatal
+#define fatal2 fatal
+#define fatal3 fatal
+#define fatal4 fatal
+#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..f0b5223
--- /dev/null
+++ b/gnu/usr.bin/patch/version.c
@@ -0,0 +1,25 @@
+/* $Header: version.c,v 2.0 86/09/17 15:40:11 lwall Exp $
+ *
+ * $Log: version.c,v $
+ * Revision 2.0 86/09/17 15:40:11 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#include "EXTERN.h"
+#include "common.h"
+#include "util.h"
+#include "INTERN.h"
+#include "patchlevel.h"
+#include "version.h"
+
+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..08fe68d
--- /dev/null
+++ b/gnu/usr.bin/patch/version.h
@@ -0,0 +1,9 @@
+/* $Header: version.h,v 2.0 86/09/17 15:40:14 lwall Exp $
+ *
+ * $Log: version.h,v $
+ * Revision 2.0 86/09/17 15:40:14 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+void version();
diff --git a/gnu/usr.bin/pr/COPYING b/gnu/usr.bin/pr/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/gnu/usr.bin/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
+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/pr/Makefile b/gnu/usr.bin/pr/Makefile
new file mode 100644
index 0000000..d651c20
--- /dev/null
+++ b/gnu/usr.bin/pr/Makefile
@@ -0,0 +1,11 @@
+PROG= pr
+SRCS= pr.c getopt.c getopt1.c error.c xmalloc.c version.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 -DDHAVE_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/pr/error.c b/gnu/usr.bin/pr/error.c
new file mode 100644
index 0000000..41d66fb
--- /dev/null
+++ b/gnu/usr.bin/pr/error.c
@@ -0,0 +1,117 @@
+/* error.c -- error handler for noninteractive utilities
+ 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
+ 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. */
+
+#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>
+
+#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/pr/getopt.c b/gnu/usr.bin/pr/getopt.c
new file mode 100644
index 0000000..7a4673b
--- /dev/null
+++ b/gnu/usr.bin/pr/getopt.c
@@ -0,0 +1,757 @@
+/* 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
+#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__
+/* 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.
+ (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 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/pr/getopt.h b/gnu/usr.bin/pr/getopt.h
new file mode 100644
index 0000000..45541f5
--- /dev/null
+++ b/gnu/usr.bin/pr/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/pr/getopt1.c b/gnu/usr.bin/pr/getopt1.c
new file mode 100644
index 0000000..f784b57
--- /dev/null
+++ b/gnu/usr.bin/pr/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/pr/pr.1 b/gnu/usr.bin/pr/pr.1
new file mode 100644
index 0000000..814f4e1
--- /dev/null
+++ b/gnu/usr.bin/pr/pr.1
@@ -0,0 +1,103 @@
+.TH PR 1L \" -*- nroff -*-
+.SH NAME
+pr \- convert text files for printing
+.SH SYNOPSIS
+.B pr
+[+PAGE] [\-COLUMN] [\-abcdfFmrtv] [\-e[in-tab-char[in-tab-width]]]
+[\-h header] [\-i[out-tab-char[out-tab-width]]] [\-l page-length]
+[\-n[number-separator[digits]]] [\-o left-margin]
+[\-s[column-separator]] [\-w page-width] [\-\-help] [\-\-version] [file...]
+.SH DESCRIPTION
+This manual page
+documents the GNU version of
+.BR pr .
+.B pr
+prints on the standard output a paginated and optionally multicolumn
+copy of the text files given on the command line, or of the standard
+input if no files are given or when the file name `\-' is encountered.
+Form feeds in the input cause page breaks in the output.
+.SS OPTIONS
+.TP
+.I \+PAGE
+Begin printing with page \fIPAGE\fP.
+.TP
+.I \-COLUMN
+Produce \fICOLUMN\fP-column output and print columns down. The column
+width is automatically decreased as \fICOLUMN\fP increases; unless you
+use the \fI\-w\fP option to increase the page width as well, this
+option might cause some columns to be truncated.
+.TP
+.I \-a
+Print columns across rather than down.
+.TP
+.I \-b
+Balance columns on the last page.
+.TP
+.I \-c
+Print control characters using hat notation (e.g., `^G'); print other
+unprintable characters in octal backslash notation.
+.TP
+.I \-d
+Double space the output.
+.TP
+.I "\-e[in-tab-char[in-tab-width]]"
+Expand tabs to spaces on input. Optional argument \fIin-tab-char\fP
+is the input tab character, default tab. Optional argument
+\fIin-tab-width\fP is the input tab character's width, default 8.
+.TP
+.I "\-F, \-f"
+Use a formfeed instead of newlines to separate output pages.
+.TP
+.I "\-h header"
+Replace the filename in the header with the string \fIheader\fP.
+.TP
+.I "\-\-help"
+Print a usage message and exit with a non-zero status.
+.TP
+.I "\-i[out-tab-char[out-tab-width]]"
+Replace spaces with tabs on output. Optional argument
+\fIout-tab-char\fP is the output tab character, default tab.
+Optional argument \fIout-tab-width\fP is the output tab character's
+width, default 8.
+.TP
+.I "\-l page-length"
+Set the page length to \fIpage-length\fP lines. The default is 66.
+If \fIpage-length\fP is less than 10, the headers and footers are
+omitted, as if the \fI\-t\fP option had been given.
+.TP
+.I \-m
+Print all files in parallel, one in each column.
+.TP
+.I "\-n[number-separator[digits]]"
+Precede each column with a line number; with parallel files, precede
+each line with a line number. Optional argument
+\fInumber-separator\fP is the character to print after each number,
+default tab. Optional argument \fIdigits\fP is the number of digits
+per line number, default 5.
+.TP
+.I "\-o left-margin"
+Offset each line with a margin \fIleft-margin\fP spaces wide. The
+total page width is this offset plus the width set with the \fI\-w\fP
+option.
+.TP
+.I \-r
+Do not print a warning message when an argument file cannot be opened.
+Failure to open a file still makes the exit status nonzero, however.
+.TP
+.I "\-s[column-separator]"
+Separate columns by the single character \fIcolumn-separator\fP,
+default tab, instead of spaces.
+.TP
+.I \-t
+Do not print the 5-line header and the 5-line trailer that are
+normally on each page, and do not fill out the bottoms of pages (with
+blank lines or formfeeds).
+.TP
+.I \-v
+Print unprintable characters in octal backslash notation.
+.TP
+.I "\-\-version"
+Print version information on standard output then exit.
+.TP
+.I "\-w page-width"
+Set the page width to \fIpage-width\fP columns. The default is 72.
diff --git a/gnu/usr.bin/pr/pr.c b/gnu/usr.bin/pr/pr.c
new file mode 100644
index 0000000..8ecc2c6
--- /dev/null
+++ b/gnu/usr.bin/pr/pr.c
@@ -0,0 +1,1920 @@
+/* pr -- convert text files for printing.
+ 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, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Author: Pete TerMaat. */
+
+/* Things to watch: Sys V screws up on ...
+ pr -n -3 -s: /usr/dict/words
+ pr -m -o10 -n /usr/dict/words{,,,}
+ pr -6 -a -n -o5 /usr/dict/words
+
+ Ideas:
+
+ Keep a things_to_do list of functions to call when we know we have
+ something to print. Cleaner than current series of checks.
+
+ Improve the printing of control prefixes.
+
+
+ Options:
+
+ +PAGE Begin output at page PAGE of the output.
+
+ -COLUMN Produce output that is COLUMN columns wide and print
+ columns down.
+
+ -a Print columns across rather than down. The input
+ one
+ two
+ three
+ four
+ will be printed as
+ one two three
+ four
+
+ -b Balance columns on the last page.
+
+ -c Print unprintable characters as control prefixes.
+ Control-g is printed as ^G.
+
+ -d Double space the output.
+
+ -e[c[k]] Expand tabs to spaces on input. Optional argument C
+ is the input tab character. (Default is `\t'.) Optional
+ argument K is the input tab character's width. (Default is 8.)
+
+ -F
+ -f Use formfeeds instead of newlines to separate pages.
+
+ -h header Replace the filename in the header with the string HEADER.
+
+ -i[c[k]] Replace spaces with tabs on output. Optional argument
+ C is the output tab character. (Default is `\t'.) Optional
+ argument K is the output tab character's width. (Default
+ is 8.)
+
+ -l lines Set the page length to LINES. Default is 66.
+
+ -m Print files in parallel.
+
+ -n[c[k]] Precede each column with a line number.
+ (With parallel files, precede each line with a line
+ number.) Optional argument C is the character to print
+ after each number. (Default `\t'.) Optional argument
+ K is the number of digits per line number. (Default 5.)
+
+ -o offset Offset each line with a margin OFFSET spaces wide.
+ Total page width is the size of this offset plus the
+ width set with `-w'.
+
+ -r Ignore files that can't be opened.
+
+ -s[c] Separate each line with a character. Optional argument C is
+ the character to be used. Default is `\t'.
+
+ -t Do not print headers or footers.
+
+ -v Print unprintable characters as escape sequences.
+ Control-G becomes \007.
+
+ -w width Set the page width to WIDTH characters. */
+
+
+#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 <time.h>
+#include "system.h"
+#include "version.h"
+
+char *xmalloc ();
+char *xrealloc ();
+void error ();
+
+static int char_to_clump ();
+static int read_line ();
+static int print_page ();
+static int print_stored ();
+static int open_file ();
+static int skip_to_page ();
+static void getoptarg ();
+static void usage ();
+static void print_files ();
+static void init_header ();
+static void init_store_cols ();
+static void store_columns ();
+static void balance ();
+static void store_char ();
+static void pad_down ();
+static void read_rest_of_line ();
+static void print_char ();
+static void cleanup ();
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+/* Used with start_position in the struct COLUMN described below.
+ If start_position == ANYWHERE, we aren't truncating columns and
+ can begin printing a column anywhere. Otherwise we must pad to
+ the horizontal position start_position. */
+#define ANYWHERE 0
+
+/* Each column has one of these structures allocated for it.
+ If we're only dealing with one file, fp is the same for all
+ columns.
+
+ The general strategy is to spend time setting up these column
+ structures (storing columns if necessary), after which printing
+ is a matter of flitting from column to column and calling
+ print_func.
+
+ Parallel files, single files printing across in multiple
+ columns, and single files printing down in multiple columns all
+ fit the same printing loop.
+
+ print_func Function used to print lines in this column.
+ If we're storing this column it will be
+ print_stored(), Otherwise it will be read_line().
+
+ char_func Function used to process characters in this column.
+ If we're storing this column it will be store_char(),
+ otherwise it will be print_char().
+
+ current_line Index of the current entry in line_vector, which
+ contains the index of the first character of the
+ current line in buff[].
+
+ lines_stored Number of lines in this column which are stored in
+ buff.
+
+ lines_to_print If we're storing this column, lines_to_print is
+ the number of stored_lines which remain to be
+ printed. Otherwise it is the number of lines
+ we can print without exceeding lines_per_body.
+
+ start_position The horizontal position we want to be in before we
+ print the first character in this column.
+
+ numbered True means precede this column with a line number. */
+
+struct COLUMN
+{
+ FILE *fp; /* Input stream for this column. */
+ char *name; /* File name. */
+ enum
+ {
+ OPEN,
+ ON_HOLD, /* Hit a form feed. */
+ CLOSED
+ } status; /* Status of the file pointer. */
+ int (*print_func) (); /* Func to print lines in this col. */
+ void (*char_func) (); /* Func to print/store chars in this col. */
+ int current_line; /* Index of current place in line_vector. */
+ int lines_stored; /* Number of lines stored in buff. */
+ int lines_to_print; /* No. lines stored or space left on page. */
+ int start_position; /* Horizontal position of first char. */
+ int numbered;
+};
+
+typedef struct COLUMN COLUMN;
+
+#define NULLCOL (COLUMN *)0
+
+/* The name under which this program was invoked. */
+char *program_name;
+
+/* All of the columns to print. */
+static COLUMN *column_vector;
+
+/* When printing a single file in multiple downward columns,
+ we store the leftmost columns contiguously in buff.
+ To print a line from buff, get the index of the first char
+ from line_vector[i], and print up to line_vector[i + 1]. */
+static char *buff;
+
+/* Index of the position in buff where the next character
+ will be stored. */
+static int buff_current;
+
+/* The number of characters in buff.
+ Used for allocation of buff and to detect overflow of buff. */
+static int buff_allocated;
+
+/* Array of indices into buff.
+ Each entry is an index of the first character of a line.
+ This is used when storing lines to facilitate shuffling when
+ we do column balancing on the last page. */
+static int *line_vector;
+
+/* Array of horizonal positions.
+ For each line in line_vector, end_vector[line] is the horizontal
+ position we are in after printing that line. We keep track of this
+ so that we know how much we need to pad to prepare for the next
+ column. */
+static int *end_vector;
+
+/* (-m) True means we're printing multiple files in parallel. */
+static int parallel_files = FALSE;
+
+/* (-[0-9]+) True means we're given an option explicitly specifying
+ number of columns. Used to detect when this option is used with -m. */
+static int explicit_columns = FALSE;
+
+/* (-t) True means we're printing headers and footers. */
+static int extremities = TRUE;
+
+/* True means we need to print a header as soon as we know we've got input
+ to print after it. */
+static int print_a_header;
+
+/* (-h) True means we're using the standard header rather than a
+ customized one specified by the -h flag. */
+static int standard_header = TRUE;
+
+/* (-f) True means use formfeeds instead of newlines to separate pages. */
+static int use_form_feed = FALSE;
+
+/* True means we have read the standard input. */
+static int have_read_stdin = FALSE;
+
+/* True means the -a flag has been given. */
+static int print_across_flag = FALSE;
+
+/* True means we're printing one file in multiple (>1) downward columns. */
+static int storing_columns = TRUE;
+
+/* (-b) True means balance columns on the last page as Sys V does. */
+static int balance_columns = FALSE;
+
+/* (-l) Number of lines on a page, including header and footer lines. */
+static int lines_per_page = 66;
+
+/* Number of lines in the header and footer can be reset to 0 using
+ the -t flag. */
+static int lines_per_header = 5;
+static int lines_per_body;
+static int lines_per_footer = 5;
+
+/* (-w) Width in characters of the page. Does not include the width of
+ the margin. */
+static int chars_per_line = 72;
+
+/* Number of characters in a column. Based on the gutter and page widths. */
+static int chars_per_column;
+
+/* (-e) True means convert tabs to spaces on input. */
+static int untabify_input = FALSE;
+
+/* (-e) The input tab character. */
+static char input_tab_char = '\t';
+
+/* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ...
+ where the leftmost column is 1. */
+static int chars_per_input_tab = 8;
+
+/* (-i) True means convert spaces to tabs on output. */
+static int tabify_output = FALSE;
+
+/* (-i) The output tab character. */
+static char output_tab_char = '\t';
+
+/* (-i) The width of the output tab. */
+static int chars_per_output_tab = 8;
+
+/* Keeps track of pending white space. When we hit a nonspace
+ character after some whitespace, we print whitespace, tabbing
+ if necessary to get to output_position + spaces_not_printed. */
+static int spaces_not_printed;
+
+/* Number of spaces between columns (though tabs can be used when possible to
+ use up the equivalent amount of space). Not sure if this is worth making
+ a flag for. BSD uses 0, Sys V uses 1. Sys V looks better. */
+static int chars_per_gutter = 1;
+
+/* (-o) Number of spaces in the left margin (tabs used when possible). */
+static int chars_per_margin = 0;
+
+/* Position where the next character will fall.
+ Leftmost position is 0 + chars_per_margin.
+ Rightmost position is chars_per_margin + chars_per_line - 1.
+ This is important for converting spaces to tabs on output. */
+static int output_position;
+
+/* Horizontal position relative to the current file.
+ (output_position depends on where we are on the page;
+ input_position depends on where we are in the file.)
+ Important for converting tabs to spaces on input. */
+static int input_position;
+
+/* Count number of failed opens so we can exit with non-zero
+ status if there were any. */
+static int failed_opens = 0;
+
+/* The horizontal position we'll be at after printing a tab character
+ of width c_ from the position h_. */
+#define pos_after_tab(c_, h_) h_ - h_ % c_ + c_
+
+/* The number of spaces taken up if we print a tab character with width
+ c_ from position h_. */
+#define tab_width(c_, h_) - h_ % c_ + c_
+
+/* (-NNN) Number of columns of text to print. */
+static int columns = 1;
+
+/* (+NNN) Page number on which to begin printing. */
+static int first_page_number = 1;
+
+/* Number of files open (not closed, not on hold). */
+static int files_ready_to_read = 0;
+
+/* Current page number. Displayed in header. */
+static int page_number;
+
+/* Current line number. Displayed when -n flag is specified.
+
+ When printing files in parallel (-m flag), line numbering is as follows:
+ 1 foo goo moo
+ 2 hoo too zoo
+
+ When printing files across (-a flag), ...
+ 1 foo 2 moo 3 goo
+ 4 hoo 3 too 6 zoo
+
+ Otherwise, line numbering is as follows:
+ 1 foo 3 goo 5 too
+ 2 moo 4 hoo 6 zoo */
+static int line_number;
+
+/* (-n) True means lines should be preceded by numbers. */
+static int numbered_lines = FALSE;
+
+/* (-n) Character which follows each line number. */
+static char number_separator = '\t';
+
+/* (-n) Width in characters of a line number. */
+static int chars_per_number = 5;
+
+/* Used when widening the first column to accommodate numbers -- only
+ needed when printing files in parallel. Includes width of both the
+ number and the number_separator. */
+static int number_width;
+
+/* Buffer sprintf uses to format a line number. */
+static char *number_buff;
+
+/* (-v) True means unprintable characters are printed as escape sequences.
+ control-g becomes \007. */
+static int use_esc_sequence = FALSE;
+
+/* (-c) True means unprintable characters are printed as control prefixes.
+ control-g becomes ^G. */
+static int use_cntrl_prefix = FALSE;
+
+/* (-d) True means output is double spaced. */
+static int double_space = FALSE;
+
+/* Number of files opened initially in init_files. Should be 1
+ unless we're printing multiple files in parallel. */
+static int total_files = 0;
+
+/* (-r) True means don't complain if we can't open a file. */
+static int ignore_failed_opens = FALSE;
+
+/* (-s) True means we separate columns with a specified character. */
+static int use_column_separator = FALSE;
+
+/* Character used to separate columns if the the -s flag has been specified. */
+static char column_separator = '\t';
+
+/* Number of separator characters waiting to be printed as soon as we
+ know that we have any input remaining to be printed. */
+static int separators_not_printed;
+
+/* Position we need to pad to, as soon as we know that we have input
+ remaining to be printed. */
+static int padding_not_printed;
+
+/* True means we should pad the end of the page. Remains false until we
+ know we have a page to print. */
+static int pad_vertically;
+
+/* (-h) String of characters used in place of the filename in the header. */
+static char *custom_header;
+
+/* String containing the date, filename or custom header, and "Page ". */
+static char *header;
+
+static int *clump_buff;
+
+/* True means we truncate lines longer than chars_per_column. */
+static int truncate_lines = FALSE;
+
+/* If non-zero, display usage information and exit. */
+static int show_help;
+
+/* If non-zero, print the version on standard output then exit. */
+static int show_version;
+
+static struct option const long_options[] =
+{
+ {"help", no_argument, &show_help, 1},
+ {"version", no_argument, &show_version, 1},
+ {0, 0, 0, 0}
+};
+
+/* Return the number of columns that have either an open file or
+ stored lines. */
+
+static int
+cols_ready_to_print ()
+{
+ COLUMN *q;
+ int i;
+ int n;
+
+ n = 0;
+ for (q = column_vector, i = 0; i < columns; ++q, ++i)
+ if (q->status == OPEN ||
+ (storing_columns && q->lines_stored > 0 && q->lines_to_print > 0))
+ ++n;
+ return n;
+}
+
+void
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int accum = 0;
+ int n_files;
+ char **file_names;
+
+ program_name = argv[0];
+
+ n_files = 0;
+ file_names = (argc > 1
+ ? (char **) xmalloc ((argc - 1) * sizeof (char *))
+ : NULL);
+
+ while (1)
+ {
+ c = getopt_long (argc, argv,
+ "-0123456789abcde::fFh:i::l:mn::o:rs::tvw:",
+ long_options, (int *) 0);
+ if (c == 1) /* Non-option argument. */
+ {
+ char *s;
+ s = optarg;
+ if (*s == '+')
+ {
+ ++s;
+ if (!ISDIGIT (*s))
+ {
+ error (0, 0, "`+' requires a numeric argument");
+ usage (2);
+ }
+ /* FIXME: use strtol */
+ first_page_number = atoi (s);
+ }
+ else
+ {
+ file_names[n_files++] = optarg;
+ }
+ }
+ else
+ {
+ if (ISDIGIT (c))
+ {
+ accum = accum * 10 + c - '0';
+ continue;
+ }
+ else
+ {
+ if (accum > 0)
+ {
+ columns = accum;
+ explicit_columns = TRUE;
+ accum = 0;
+ }
+ }
+ }
+
+ if (c == 1)
+ continue;
+
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case 0: /* getopt long option */
+ break;
+
+ case 'a':
+ print_across_flag = TRUE;
+ storing_columns = FALSE;
+ break;
+ case 'b':
+ balance_columns = TRUE;
+ break;
+ case 'c':
+ use_cntrl_prefix = TRUE;
+ break;
+ case 'd':
+ double_space = TRUE;
+ break;
+ case 'e':
+ if (optarg)
+ getoptarg (optarg, 'e', &input_tab_char,
+ &chars_per_input_tab);
+ /* Could check tab width > 0. */
+ untabify_input = TRUE;
+ break;
+ case 'f':
+ case 'F':
+ use_form_feed = TRUE;
+ break;
+ case 'h':
+ custom_header = optarg;
+ standard_header = FALSE;
+ break;
+ case 'i':
+ if (optarg)
+ getoptarg (optarg, 'i', &output_tab_char,
+ &chars_per_output_tab);
+ /* Could check tab width > 0. */
+ tabify_output = TRUE;
+ break;
+ case 'l':
+ lines_per_page = atoi (optarg);
+ break;
+ case 'm':
+ parallel_files = TRUE;
+ storing_columns = FALSE;
+ break;
+ case 'n':
+ numbered_lines = TRUE;
+ if (optarg)
+ getoptarg (optarg, 'n', &number_separator,
+ &chars_per_number);
+ break;
+ case 'o':
+ chars_per_margin = atoi (optarg);
+ break;
+ case 'r':
+ ignore_failed_opens = TRUE;
+ break;
+ case 's':
+ use_column_separator = TRUE;
+ if (optarg)
+ {
+ char *s;
+ s = optarg;
+ column_separator = *s;
+ if (*++s)
+ {
+ fprintf (stderr, "\
+%s: extra characters in the argument to the `-s' option: `%s'\n",
+ program_name, s);
+ usage (2);
+ }
+ }
+ break;
+ case 't':
+ extremities = FALSE;
+ break;
+ case 'v':
+ use_esc_sequence = TRUE;
+ break;
+ case 'w':
+ chars_per_line = atoi (optarg);
+ break;
+ default:
+ usage (2);
+ break;
+ }
+ }
+
+ if (show_version)
+ {
+ printf ("%s\n", version_string);
+ exit (0);
+ }
+
+ if (show_help)
+ usage (0);
+
+ if (parallel_files && explicit_columns)
+ error (1, 0,
+ "Cannot specify number of columns when printing in parallel.");
+
+ if (parallel_files && print_across_flag)
+ error (1, 0,
+ "Cannot specify both printing across and printing in parallel.");
+
+ for ( ; optind < argc; optind++)
+ {
+ file_names[n_files++] = argv[optind];
+ }
+
+ if (n_files == 0)
+ {
+ /* No file arguments specified; read from standard input. */
+ print_files (0, (char **) 0);
+ }
+ else
+ {
+ if (parallel_files)
+ print_files (n_files, file_names);
+ else
+ {
+ int i;
+ for (i=0; i<n_files; i++)
+ print_files (1, &file_names[i]);
+ }
+ }
+
+ cleanup ();
+
+ if (have_read_stdin && fclose (stdin) == EOF)
+ error (1, errno, "standard input");
+ if (ferror (stdout) || fclose (stdout) == EOF)
+ error (1, errno, "write error");
+ if (failed_opens > 0)
+ exit(1);
+ exit (0);
+}
+
+/* Parse options of the form -scNNN.
+
+ Example: -nck, where 'n' is the option, c is the optional number
+ separator, and k is the optional width of the field used when printing
+ a number. */
+
+static void
+getoptarg (arg, switch_char, character, number)
+ char *arg, switch_char, *character;
+ int *number;
+{
+ if (!ISDIGIT (*arg))
+ *character = *arg++;
+ if (*arg)
+ {
+ if (ISDIGIT (*arg))
+ *number = atoi (arg);
+ else
+ {
+ fprintf (stderr, "\
+%s: extra characters in the argument to the `-%c' option: `%s'\n",
+ program_name, switch_char, arg);
+ usage (2);
+ }
+ }
+}
+
+/* Set parameters related to formatting. */
+
+static void
+init_parameters (number_of_files)
+ int number_of_files;
+{
+ int chars_used_by_number = 0;
+
+ lines_per_body = lines_per_page - lines_per_header - lines_per_footer;
+ if (lines_per_body <= 0)
+ extremities = FALSE;
+ if (extremities == FALSE)
+ lines_per_body = lines_per_page;
+
+ if (double_space)
+ lines_per_body = lines_per_body / 2;
+
+ /* If input is stdin, cannot print parallel files. BSD dumps core
+ on this. */
+ if (number_of_files == 0)
+ parallel_files = FALSE;
+
+ if (parallel_files)
+ columns = number_of_files;
+
+ /* Tabification is assumed for multiple columns. */
+ if (columns > 1)
+ {
+ if (!use_column_separator)
+ truncate_lines = TRUE;
+
+ untabify_input = TRUE;
+ tabify_output = TRUE;
+ }
+ else
+ storing_columns = FALSE;
+
+ if (numbered_lines)
+ {
+ if (number_separator == input_tab_char)
+ {
+ number_width = chars_per_number +
+ tab_width (chars_per_input_tab,
+ (chars_per_margin + chars_per_number));
+ }
+ else
+ number_width = chars_per_number + 1;
+ /* The number is part of the column width unless we are
+ printing files in parallel. */
+ if (parallel_files)
+ chars_used_by_number = number_width;
+ }
+
+ chars_per_column = (chars_per_line - chars_used_by_number -
+ (columns - 1) * chars_per_gutter) / columns;
+
+ if (chars_per_column < 1)
+ error (1, 0, "page width too narrow");
+
+ if (numbered_lines)
+ {
+ if (number_buff != (char *) 0)
+ free (number_buff);
+ number_buff = (char *)
+ xmalloc (2 * chars_per_number * sizeof (char));
+ }
+
+ /* Pick the maximum between the tab width and the width of an
+ escape sequence. */
+ if (clump_buff != (int *) 0)
+ free (clump_buff);
+ clump_buff = (int *) xmalloc ((chars_per_input_tab > 4
+ ? chars_per_input_tab : 4) * sizeof (int));
+}
+
+/* Open the necessary files,
+ maintaining a COLUMN structure for each column.
+
+ With multiple files, each column p has a different p->fp.
+ With single files, each column p has the same p->fp.
+ Return 1 if (number_of_files > 0) and no files can be opened,
+ 0 otherwise. */
+
+static int
+init_fps (number_of_files, av)
+ int number_of_files;
+ char **av;
+{
+ int i, files_left;
+ COLUMN *p;
+ FILE *firstfp;
+ char *firstname;
+
+ total_files = 0;
+
+ if (column_vector != NULLCOL)
+ free ((char *) column_vector);
+ column_vector = (COLUMN *) xmalloc (columns * sizeof (COLUMN));
+
+ if (parallel_files)
+ {
+ files_left = number_of_files;
+ for (p = column_vector; files_left--; ++p, ++av)
+ {
+ if (open_file (*av, p) == 0)
+ {
+ --p;
+ --columns;
+ }
+ }
+ if (columns == 0)
+ return 1;
+ init_header ("", -1);
+ }
+ else
+ {
+ p = column_vector;
+ if (number_of_files > 0)
+ {
+ if (open_file (*av, p) == 0)
+ return 1;
+ init_header (*av, fileno (p->fp));
+ }
+ else
+ {
+ p->name = "standard input";
+ p->fp = stdin;
+ have_read_stdin = TRUE;
+ p->status = OPEN;
+ ++total_files;
+ init_header ("", -1);
+ }
+
+ firstname = p->name;
+ firstfp = p->fp;
+ for (i = columns - 1, ++p; i; --i, ++p)
+ {
+ p->name = firstname;
+ p->fp = firstfp;
+ p->status = OPEN;
+ }
+ }
+ files_ready_to_read = total_files;
+ return 0;
+}
+
+/* Determine print_func and char_func, the functions
+ used by each column for printing and/or storing.
+
+ Determine the horizontal position desired when we begin
+ printing a column (p->start_position). */
+
+static void
+init_funcs ()
+{
+ int i, h, h_next;
+ COLUMN *p;
+
+ h = chars_per_margin;
+
+ if (use_column_separator)
+ h_next = ANYWHERE;
+ else
+ {
+ /* When numbering lines of parallel files, we enlarge the
+ first column to accomodate the number. Looks better than
+ the Sys V approach. */
+ if (parallel_files && numbered_lines)
+ h_next = h + chars_per_column + number_width;
+ else
+ h_next = h + chars_per_column;
+ }
+
+ /* This loop takes care of all but the rightmost column. */
+
+ for (p = column_vector, i = 1; i < columns; ++p, ++i)
+ {
+ if (storing_columns) /* One file, multi columns down. */
+ {
+ p->char_func = store_char;
+ p->print_func = print_stored;
+ }
+ else
+ /* One file, multi columns across; or parallel files. */
+ {
+ p->char_func = print_char;
+ p->print_func = read_line;
+ }
+
+ /* Number only the first column when printing files in
+ parallel. */
+ p->numbered = numbered_lines && (!parallel_files || i == 1);
+ p->start_position = h;
+
+ /* If we're using separators, all start_positions are
+ ANYWHERE, except the first column's start_position when
+ using a margin. */
+
+ if (use_column_separator)
+ {
+ h = ANYWHERE;
+ h_next = ANYWHERE;
+ }
+ else
+ {
+ h = h_next + chars_per_gutter;
+ h_next = h + chars_per_column;
+ }
+ }
+
+ /* The rightmost column.
+
+ Doesn't need to be stored unless we intend to balance
+ columns on the last page. */
+ if (storing_columns && balance_columns)
+ {
+ p->char_func = store_char;
+ p->print_func = print_stored;
+ }
+ else
+ {
+ p->char_func = print_char;
+ p->print_func = read_line;
+ }
+
+ p->numbered = numbered_lines && (!parallel_files || i == 1);
+ p->start_position = h;
+}
+
+/* Open a file. Return nonzero if successful, zero if failed. */
+
+static int
+open_file (name, p)
+ char *name;
+ COLUMN *p;
+{
+ if (!strcmp (name, "-"))
+ {
+ p->name = "standard input";
+ p->fp = stdin;
+ have_read_stdin = 1;
+ }
+ else
+ {
+ p->name = name;
+ p->fp = fopen (name, "r");
+ }
+ if (p->fp == NULL)
+ {
+ ++failed_opens;
+ if (!ignore_failed_opens)
+ error (0, errno, "%s", name);
+ return 0;
+ }
+ p->status = OPEN;
+ ++total_files;
+ return 1;
+}
+
+/* Close the file in P.
+
+ If we aren't dealing with multiple files in parallel, we change
+ the status of all columns in the column list to reflect the close. */
+
+static void
+close_file (p)
+ COLUMN *p;
+{
+ COLUMN *q;
+ int i;
+
+ if (p->status == CLOSED)
+ return;
+ if (ferror (p->fp))
+ error (1, errno, "%s", p->name);
+ if (p->fp != stdin && fclose (p->fp) == EOF)
+ error (1, errno, "%s", p->name);
+
+ if (!parallel_files)
+ {
+ for (q = column_vector, i = columns; i; ++q, --i)
+ {
+ q->status = CLOSED;
+ if (q->lines_stored == 0)
+ {
+ q->lines_to_print = 0;
+ }
+ }
+ }
+ else
+ {
+ p->status = CLOSED;
+ p->lines_to_print = 0;
+ }
+
+ --files_ready_to_read;
+}
+
+/* Put a file on hold until we start a new page,
+ since we've hit a form feed.
+
+ If we aren't dealing with parallel files, we must change the
+ status of all columns in the column list. */
+
+static void
+hold_file (p)
+ COLUMN *p;
+{
+ COLUMN *q;
+ int i;
+
+ if (!parallel_files)
+ for (q = column_vector, i = columns; i; ++q, --i)
+ q->status = ON_HOLD;
+ else
+ p->status = ON_HOLD;
+ p->lines_to_print = 0;
+ --files_ready_to_read;
+}
+
+/* Undo hold_file -- go through the column list and change any
+ ON_HOLD columns to OPEN. Used at the end of each page. */
+
+static void
+reset_status ()
+{
+ int i = columns;
+ COLUMN *p;
+
+ for (p = column_vector; i; --i, ++p)
+ if (p->status == ON_HOLD)
+ {
+ p->status = OPEN;
+ files_ready_to_read++;
+ }
+}
+
+/* Print a single file, or multiple files in parallel.
+
+ Set up the list of columns, opening the necessary files.
+ Allocate space for storing columns, if necessary.
+ Skip to first_page_number, if user has asked to skip leading pages.
+ Determine which functions are appropriate to store/print lines
+ in each column.
+ Print the file(s). */
+
+static void
+print_files (number_of_files, av)
+ int number_of_files;
+ char **av;
+{
+ init_parameters (number_of_files);
+ if (init_fps (number_of_files, av))
+ return;
+ if (storing_columns)
+ init_store_cols ();
+
+ if (first_page_number > 1)
+ {
+ if (!skip_to_page (first_page_number))
+ return;
+ else
+ page_number = first_page_number;
+ }
+ else
+ page_number = 1;
+
+ init_funcs ();
+
+ line_number = 1;
+ while (print_page ())
+ ;
+}
+
+/* Generous estimate of number of characters taken up by "Jun 7 00:08 " and
+ "Page NNNNN". */
+#define CHARS_FOR_DATE_AND_PAGE 50
+
+/* Initialize header information.
+ If DESC is non-negative, it is a file descriptor open to
+ FILENAME for reading.
+
+ Allocate space for a header string,
+ Determine the time, insert file name or user-specified string.
+
+ It might be nice to have a "blank headers" option, since
+ pr -h "" still prints the date and page number. */
+
+static void
+init_header (filename, desc)
+ char *filename;
+ int desc;
+{
+ int chars_per_header;
+ char *f = filename;
+ char *t, *middle;
+ struct stat st;
+
+ if (filename == 0)
+ f = "";
+
+ /* If parallel files or standard input, use current time. */
+ if (desc < 0 || !strcmp (filename, "-") || fstat (desc, &st))
+ st.st_mtime = time ((time_t *) 0);
+ t = ctime (&st.st_mtime);
+
+ t[16] = '\0'; /* Mark end of month and time string. */
+ t[24] = '\0'; /* Mark end of year string. */
+
+ middle = standard_header ? f : custom_header;
+
+ chars_per_header = strlen (middle) + CHARS_FOR_DATE_AND_PAGE + 1;
+ if (header != (char *) 0)
+ free (header);
+ header = (char *) xmalloc (chars_per_header * sizeof (char));
+
+ sprintf (header, "%s %s %s Page", &t[4], &t[20], middle);
+}
+
+/* Set things up for printing a page
+
+ Scan through the columns ...
+ Determine which are ready to print
+ (i.e., which have lines stored or open files)
+ Set p->lines_to_print appropriately
+ (to p->lines_stored if we're storing, or lines_per_body
+ if we're reading straight from the file)
+ Keep track of this total so we know when to stop printing */
+
+static void
+init_page ()
+{
+ int j;
+ COLUMN *p;
+
+ if (storing_columns)
+ {
+ store_columns ();
+ for (j = columns - 1, p = column_vector; j; --j, ++p)
+ {
+ p->lines_to_print = p->lines_stored;
+ }
+
+ /* Last column. */
+ if (balance_columns)
+ {
+ p->lines_to_print = p->lines_stored;
+ }
+ /* Since we're not balancing columns, we don't need to store
+ the rightmost column. Read it straight from the file. */
+ else
+ {
+ if (p->status == OPEN)
+ {
+ p->lines_to_print = lines_per_body;
+ }
+ else
+ p->lines_to_print = 0;
+ }
+ }
+ else
+ for (j = columns, p = column_vector; j; --j, ++p)
+ if (p->status == OPEN)
+ {
+ p->lines_to_print = lines_per_body;
+ }
+ else
+ p->lines_to_print = 0;
+}
+
+/* Print one page.
+
+ As long as there are lines left on the page and columns ready to print,
+ Scan across the column list
+ if the column has stored lines or the file is open
+ pad to the appropriate spot
+ print the column
+ pad the remainder of the page with \n or \f as requested
+ reset the status of all files -- any files which where on hold because
+ of formfeeds are now put back into the lineup. */
+
+static int
+print_page ()
+{
+ int j;
+ int lines_left_on_page;
+ COLUMN *p;
+
+ /* Used as an accumulator (with | operator) of successive values of
+ pad_vertically. The trick is to set pad_vertically
+ to zero before each run through the inner loop, then after that
+ loop, it tells us whether a line was actually printed (whether a
+ newline needs to be output -- or two for double spacing). But those
+ values have to be accumulated (in pv) so we can invoke pad_down
+ properly after the outer loop completes. */
+ int pv;
+
+ init_page ();
+
+ if (cols_ready_to_print () == 0)
+ return FALSE;
+
+ if (extremities)
+ print_a_header = TRUE;
+
+ /* Don't pad unless we know a page was printed. */
+ pad_vertically = FALSE;
+ pv = FALSE;
+
+ lines_left_on_page = lines_per_body;
+ if (double_space)
+ lines_left_on_page *= 2;
+
+ while (lines_left_on_page > 0 && cols_ready_to_print () > 0)
+ {
+ output_position = 0;
+ spaces_not_printed = 0;
+ separators_not_printed = 0;
+ pad_vertically = FALSE;
+
+ for (j = 1, p = column_vector; j <= columns; ++j, ++p)
+ {
+ input_position = 0;
+ if (p->lines_to_print > 0)
+ {
+ padding_not_printed = p->start_position;
+
+ if (!(p->print_func) (p))
+ read_rest_of_line (p);
+ pv |= pad_vertically;
+
+ if (use_column_separator)
+ ++separators_not_printed;
+
+ --p->lines_to_print;
+ if (p->lines_to_print <= 0)
+ {
+ if (cols_ready_to_print () <= 0)
+ break;
+ }
+ }
+ }
+
+ if (pad_vertically)
+ {
+ putchar ('\n');
+ --lines_left_on_page;
+ }
+
+ if (double_space && pv && extremities)
+ {
+ putchar ('\n');
+ --lines_left_on_page;
+ }
+ }
+
+ pad_vertically = pv;
+
+ if (pad_vertically && extremities)
+ pad_down (lines_left_on_page + lines_per_footer);
+
+ reset_status (); /* Change ON_HOLD to OPEN. */
+
+ return TRUE; /* More pages to go. */
+}
+
+/* Allocate space for storing columns.
+
+ This is necessary when printing multiple columns from a single file.
+ Lines are stored consecutively in buff, separated by '\0'.
+ (We can't use a fixed offset since with the '-s' flag lines aren't
+ truncated.)
+
+ We maintain a list (line_vector) of pointers to the beginnings
+ of lines in buff. We allocate one more than the number of lines
+ because the last entry tells us the index of the last character,
+ which we need to know in order to print the last line in buff. */
+
+static void
+init_store_cols ()
+{
+ int total_lines = lines_per_body * columns;
+ int chars_if_truncate = total_lines * (chars_per_column + 1);
+
+ if (line_vector != (int *) 0)
+ free ((int *) line_vector);
+ line_vector = (int *) xmalloc ((total_lines + 1) * sizeof (int *));
+
+ if (end_vector != (int *) 0)
+ free ((int *) end_vector);
+ end_vector = (int *) xmalloc (total_lines * sizeof (int *));
+
+ if (buff != (char *) 0)
+ free (buff);
+ buff_allocated = use_column_separator ? 2 * chars_if_truncate
+ : chars_if_truncate; /* Tune this. */
+ buff = (char *) xmalloc (buff_allocated * sizeof (char));
+}
+
+/* Store all but the rightmost column.
+ (Used when printing a single file in multiple downward columns)
+
+ For each column
+ set p->current_line to be the index in line_vector of the
+ first line in the column
+ For each line in the column
+ store the line in buff
+ add to line_vector the index of the line's first char
+ buff_start is the index in buff of the first character in the
+ current line. */
+
+static void
+store_columns ()
+{
+ int i, j;
+ int line = 0;
+ int buff_start;
+ int last_col; /* The rightmost column which will be saved in buff */
+ COLUMN *p;
+
+ buff_current = 0;
+ buff_start = 0;
+
+ if (balance_columns)
+ last_col = columns;
+ else
+ last_col = columns - 1;
+
+ for (i = 1, p = column_vector; i <= last_col; ++i, ++p)
+ p->lines_stored = 0;
+
+ for (i = 1, p = column_vector; i <= last_col && files_ready_to_read;
+ ++i, ++p)
+ {
+ p->current_line = line;
+ for (j = lines_per_body; j && files_ready_to_read; --j)
+
+ if (p->status == OPEN) /* Redundant. Clean up. */
+ {
+ input_position = 0;
+
+ if (!read_line (p, i))
+ read_rest_of_line (p);
+
+ if (p->status == OPEN
+ || buff_start != buff_current)
+ {
+ ++p->lines_stored;
+ line_vector[line] = buff_start;
+ end_vector[line++] = input_position;
+ buff_start = buff_current;
+ }
+ }
+ }
+
+ /* Keep track of the location of the last char in buff. */
+ line_vector[line] = buff_start;
+
+ if (balance_columns && p->lines_stored != lines_per_body)
+ balance (line);
+}
+
+static void
+balance (total_stored)
+ int total_stored;
+{
+ COLUMN *p;
+ int i, lines;
+ int first_line = 0;
+
+ for (i = 1, p = column_vector; i <= columns; ++i, ++p)
+ {
+ lines = total_stored / columns;
+ if (i <= total_stored % columns)
+ ++lines;
+
+ p->lines_stored = lines;
+ p->current_line = first_line;
+
+ first_line += lines;
+ }
+}
+
+/* Store a character in the buffer. */
+
+static void
+store_char (c)
+ int c;
+{
+ if (buff_current >= buff_allocated)
+ {
+ /* May be too generous. */
+ buff_allocated = 2 * buff_allocated;
+ buff = (char *) xrealloc (buff, buff_allocated * sizeof (char));
+ }
+ buff[buff_current++] = (char) c;
+}
+
+static void
+number (p)
+ COLUMN *p;
+{
+ int i;
+ char *s;
+
+ sprintf (number_buff, "%*d", chars_per_number, line_number++);
+ s = number_buff;
+ for (i = chars_per_number; i > 0; i--)
+ (p->char_func) ((int) *s++);
+
+ if (number_separator == input_tab_char)
+ {
+ i = number_width - chars_per_number;
+ while (i-- > 0)
+ (p->char_func) ((int) ' ');
+ }
+ else
+ (p->char_func) ((int) number_separator);
+
+ if (truncate_lines && !parallel_files)
+ input_position += number_width;
+}
+
+/* Print (or store) padding until the current horizontal position
+ is position. */
+
+static void
+pad_across_to (position)
+ int position;
+{
+ register int h = output_position;
+
+ if (tabify_output)
+ spaces_not_printed = position - output_position;
+ else
+ {
+ while (++h <= position)
+ putchar (' ');
+ output_position = position;
+ }
+}
+
+/* Pad to the bottom of the page.
+
+ If the user has requested a formfeed, use one.
+ Otherwise, use newlines. */
+
+static void
+pad_down (lines)
+ int lines;
+{
+ register int i;
+
+ if (use_form_feed)
+ putchar ('\f');
+ else
+ for (i = lines; i; --i)
+ putchar ('\n');
+}
+
+/* Read the rest of the line.
+
+ Read from the current column's file until an end of line is
+ hit. Used when we've truncated a line and we no longer need
+ to print or store its characters. */
+
+static void
+read_rest_of_line (p)
+ COLUMN *p;
+{
+ register int c;
+ FILE *f = p->fp;
+
+ while ((c = getc (f)) != '\n')
+ {
+ if (c == '\f')
+ {
+ hold_file (p);
+ break;
+ }
+ else if (c == EOF)
+ {
+ close_file (p);
+ break;
+ }
+ }
+}
+
+/* If we're tabifying output,
+
+ When print_char encounters white space it keeps track
+ of our desired horizontal position and delays printing
+ until this function is called. */
+
+static void
+print_white_space ()
+{
+ register int h_new;
+ register int h_old = output_position;
+ register int goal = h_old + spaces_not_printed;
+
+ while (goal - h_old > 1
+ && (h_new = pos_after_tab (chars_per_output_tab, h_old)) <= goal)
+ {
+ putchar (output_tab_char);
+ h_old = h_new;
+ }
+ while (++h_old <= goal)
+ putchar (' ');
+
+ output_position = goal;
+ spaces_not_printed = 0;
+}
+
+/* Print column separators.
+
+ We keep a count until we know that we'll be printing a line,
+ then print_separators() is called. */
+
+static void
+print_separators ()
+{
+ for (; separators_not_printed > 0; --separators_not_printed)
+ print_char (column_separator);
+}
+
+/* Print (or store, depending on p->char_func) a clump of N
+ characters. */
+
+static void
+print_clump (p, n, clump)
+ COLUMN *p;
+ int n;
+ int *clump;
+{
+ while (n--)
+ (p->char_func) (*clump++);
+}
+
+/* Print a character.
+
+ If we're tabifying, all tabs have been converted to spaces by
+ process_char(). Keep a count of consecutive spaces, and when
+ a nonspace is encountered, call print_white_space() to print the
+ required number of tabs and spaces. */
+
+static void
+print_char (c)
+ int c;
+{
+ if (tabify_output)
+ {
+ if (c == ' ')
+ {
+ ++spaces_not_printed;
+ return;
+ }
+ else if (spaces_not_printed > 0)
+ print_white_space ();
+
+ /* Nonprintables are assumed to have width 0, except '\b'. */
+ if (!ISPRINT (c))
+ {
+ if (c == '\b')
+ --output_position;
+ }
+ else
+ ++output_position;
+ }
+ putchar (c);
+}
+
+/* Skip to page PAGE before printing. */
+
+static int
+skip_to_page (page)
+ int page;
+{
+ int n, i, j;
+ COLUMN *p;
+
+ for (n = 1; n < page; ++n)
+ {
+ for (i = 1; i <= lines_per_body; ++i)
+ {
+ for (j = 1, p = column_vector; j <= columns; ++j, ++p)
+ read_rest_of_line (p);
+ }
+ reset_status ();
+ }
+ return files_ready_to_read > 0;
+}
+
+/* Print a header.
+
+ Formfeeds are assumed to use up two lines at the beginning of
+ the page. */
+
+static void
+print_header ()
+{
+ if (!use_form_feed)
+ fprintf (stdout, "\n\n");
+
+ output_position = 0;
+ pad_across_to (chars_per_margin);
+ print_white_space ();
+
+ fprintf (stdout, "%s %d\n\n\n", header, page_number++);
+
+ print_a_header = FALSE;
+ output_position = 0;
+}
+
+/* Print (or store, if p->char_func is store_char()) a line.
+
+ Read a character to determine whether we have a line or not.
+ (We may hit EOF, \n, or \f)
+
+ Once we know we have a line,
+ set pad_vertically = TRUE, meaning it's safe
+ to pad down at the end of the page, since we do have a page.
+ print a header if needed.
+ pad across to padding_not_printed if needed.
+ print any separators which need to be printed.
+ print a line number if it needs to be printed.
+
+ Print the clump which corresponds to the first character.
+
+ Enter a loop and keep printing until an end of line condition
+ exists, or until we exceed chars_per_column.
+
+ Return FALSE if we exceed chars_per_column before reading
+ an end of line character, TRUE otherwise. */
+
+static int
+read_line (p)
+ COLUMN *p;
+{
+ register int c, chars;
+ int last_input_position;
+
+ c = getc (p->fp);
+
+ last_input_position = input_position;
+ switch (c)
+ {
+ case '\f':
+ hold_file (p);
+ return TRUE;
+ case EOF:
+ close_file (p);
+ return TRUE;
+ case '\n':
+ break;
+ default:
+ chars = char_to_clump (c);
+ }
+
+ if (truncate_lines && input_position > chars_per_column)
+ {
+ input_position = last_input_position;
+ return FALSE;
+ }
+
+ if (p->char_func != store_char)
+ {
+ pad_vertically = TRUE;
+
+ if (print_a_header)
+ print_header ();
+
+ if (padding_not_printed != ANYWHERE)
+ {
+ pad_across_to (padding_not_printed);
+ padding_not_printed = ANYWHERE;
+ }
+
+ if (use_column_separator)
+ print_separators ();
+ }
+
+ if (p->numbered)
+ number (p);
+
+ if (c == '\n')
+ return TRUE;
+
+ print_clump (p, chars, clump_buff);
+
+ for (;;)
+ {
+ c = getc (p->fp);
+
+ switch (c)
+ {
+ case '\n':
+ return TRUE;
+ case '\f':
+ hold_file (p);
+ return TRUE;
+ case EOF:
+ close_file (p);
+ return TRUE;
+ }
+
+ last_input_position = input_position;
+ chars = char_to_clump (c);
+ if (truncate_lines && input_position > chars_per_column)
+ {
+ input_position = last_input_position;
+ return FALSE;
+ }
+
+ print_clump (p, chars, clump_buff);
+ }
+}
+
+/* Print a line from buff.
+
+ If this function has been called, we know we have something to
+ print. Therefore we set pad_vertically to TRUE, print
+ a header if necessary, pad across if necessary, and print
+ separators if necessary.
+
+ Return TRUE, meaning there is no need to call read_rest_of_line. */
+
+static int
+print_stored (p)
+ COLUMN *p;
+{
+ int line = p->current_line++;
+ register char *first = &buff[line_vector[line]];
+ register char *last = &buff[line_vector[line + 1]];
+
+ pad_vertically = TRUE;
+
+ if (print_a_header)
+ print_header ();
+
+ if (padding_not_printed != ANYWHERE)
+ {
+ pad_across_to (padding_not_printed);
+ padding_not_printed = ANYWHERE;
+ }
+
+ if (use_column_separator)
+ print_separators ();
+
+ while (first != last)
+ print_char (*first++);
+
+ if (spaces_not_printed == 0)
+ output_position = p->start_position + end_vector[line];
+
+ return TRUE;
+}
+
+/* Convert a character to the proper format and return the number of
+ characters in the resulting clump. Increment input_position by
+ the width of the clump.
+
+ Tabs are converted to clumps of spaces.
+ Nonprintable characters may be converted to clumps of escape
+ sequences or control prefixes.
+
+ Note: the width of a clump is not necessarily equal to the number of
+ characters in clump_buff. (e.g, the width of '\b' is -1, while the
+ number of characters is 1.) */
+
+static int
+char_to_clump (c)
+ int c;
+{
+ register int *s = clump_buff;
+ register int i;
+ char esc_buff[4];
+ int width;
+ int chars;
+
+ if (c == input_tab_char)
+ {
+ width = tab_width (chars_per_input_tab, input_position);
+
+ if (untabify_input)
+ {
+ for (i = width; i; --i)
+ *s++ = ' ';
+ chars = width;
+ }
+ else
+ {
+ *s = c;
+ chars = 1;
+ }
+
+ }
+ else if (!ISPRINT (c))
+ {
+ if (use_esc_sequence)
+ {
+ width = 4;
+ chars = 4;
+ *s++ = '\\';
+ sprintf (esc_buff, "%03o", c);
+ for (i = 0; i <= 2; ++i)
+ *s++ = (int) esc_buff[i];
+ }
+ else if (use_cntrl_prefix)
+ {
+ if (c < 0200)
+ {
+ width = 2;
+ chars = 2;
+ *s++ = '^';
+ *s++ = c ^ 0100;
+ }
+ else
+ {
+ width = 4;
+ chars = 4;
+ *s++ = '\\';
+ sprintf (esc_buff, "%03o", c);
+ for (i = 0; i <= 2; ++i)
+ *s++ = (int) esc_buff[i];
+ }
+ }
+ else if (c == '\b')
+ {
+ width = -1;
+ chars = 1;
+ *s = c;
+ }
+ else
+ {
+ width = 0;
+ chars = 1;
+ *s = c;
+ }
+ }
+ else
+ {
+ width = 1;
+ chars = 1;
+ *s = c;
+ }
+
+ input_position += width;
+ return chars;
+}
+
+/* We've just printed some files and need to clean up things before
+ looking for more options and printing the next batch of files.
+
+ Free everything we've xmalloc'ed, except `header'. */
+
+static void
+cleanup ()
+{
+ if (number_buff)
+ free (number_buff);
+ if (clump_buff)
+ free (clump_buff);
+ if (column_vector)
+ free (column_vector);
+ if (line_vector)
+ free (line_vector);
+ if (end_vector)
+ free (end_vector);
+ if (buff)
+ free (buff);
+}
+
+/* Complain, print a usage message, and die. */
+
+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\
+ +PAGE begin printing with page PAGE\n\
+ -COLUMN produce COLUMN-column output and print columns down\n\
+ -F, -f simulate formfeed with newlines on output\n\
+ -a print columns across rather than down\n\
+ -b balance columns on the last page\n\
+ -c use hat notation (^G) and octal backslash notation\n\
+ -d double space the output\n\
+ -e[CHAR[WIDTH]] expand input CHARs (TABs) to tab WIDTH (8)\n\
+ -h HEADER use HEADER instead of filename in page headers\n\
+ -i[CHAR[WIDTH]] replace spaces with CHARs (TABs) to tab WIDTH (8)\n\
+ -l PAGE_LENGTH set the page length to PAGE_LENGTH (66) lines\n\
+ -m print all files in parallel, one in each column\n\
+ -n[SEP[DIGITS]] number lines, use DIGITS (5) digits, then SEP (TAB)\n\
+ -o MARGIN offset each line with MARGIN spaces (do not affect -w)\n\
+ -r inhibit warning when a file cannot be opened\n\
+ -s[SEP] separate columns by character SEP (TAB)\n\
+ -t inhibit 5-line page headers and trailers\n\
+ -v use octal backslash notation\n\
+ -w PAGE_WIDTH set page width to PAGE_WIDTH (72) columns\n\
+ --help display this help and exit\n\
+ --version output version information and exit\n\
+\n\
+-t implied by -l N when N < 10. Without -s, columns are separated by\n\
+spaces. With no FILE, or when FILE is -, read standard input.\n\
+");
+ }
+ exit (status);
+}
diff --git a/gnu/usr.bin/pr/system.h b/gnu/usr.bin/pr/system.h
new file mode 100644
index 0000000..4aeaaea
--- /dev/null
+++ b/gnu/usr.bin/pr/system.h
@@ -0,0 +1,200 @@
+/* system-dependent definitions for textutils programs.
+ Copyright (C) 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, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the 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 before this file. */
+
+#include <sys/stat.h>
+
+#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
+#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
+#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
+#if !defined(HAVE_MKFIFO)
+#define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0))
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef _POSIX_VERSION
+off_t lseek ();
+#endif
+
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
+#include <memory.h>
+#endif
+#include <string.h>
+#ifndef index
+#define index strchr
+#endif
+#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
+#else
+#include <strings.h>
+char *memchr ();
+#endif
+
+#include <errno.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *getenv ();
+extern int errno;
+#endif
+
+#if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#endif
+
+#if !defined(SEEK_SET)
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+#ifndef _POSIX_SOURCE
+#include <sys/param.h>
+#endif
+
+/* Get or fake the disk device blocksize.
+ Usually defined by sys/param.h (if at all). */
+#if !defined(DEV_BSIZE) && defined(BSIZE)
+#define DEV_BSIZE BSIZE
+#endif
+#if !defined(DEV_BSIZE) && defined(BBSIZE) /* SGI */
+#define DEV_BSIZE BBSIZE
+#endif
+#ifndef DEV_BSIZE
+#define DEV_BSIZE 4096
+#endif
+
+/* Extract or fake data from a `struct stat'.
+ ST_BLKSIZE: Optimal I/O blocksize for the file, in bytes. */
+#ifndef HAVE_ST_BLKSIZE
+# define ST_BLKSIZE(statbuf) DEV_BSIZE
+#else /* HAVE_ST_BLKSIZE */
+/* Some systems, like Sequents, return st_blksize of 0 on pipes. */
+# define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
+ ? (statbuf).st_blksize : DEV_BSIZE)
+#endif /* HAVE_ST_BLKSIZE */
+
+#ifndef S_ISLNK
+#define lstat stat
+#endif
+
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+
+#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))
diff --git a/gnu/usr.bin/pr/version.c b/gnu/usr.bin/pr/version.c
new file mode 100644
index 0000000..64c62b19
--- /dev/null
+++ b/gnu/usr.bin/pr/version.c
@@ -0,0 +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.9";
diff --git a/gnu/usr.bin/pr/version.h b/gnu/usr.bin/pr/version.h
new file mode 100644
index 0000000..63de4fd
--- /dev/null
+++ b/gnu/usr.bin/pr/version.h
@@ -0,0 +1 @@
+extern const char *version_string;
diff --git a/gnu/usr.bin/pr/xmalloc.c b/gnu/usr.bin/pr/xmalloc.c
new file mode 100644
index 0000000..58a81b5
--- /dev/null
+++ b/gnu/usr.bin/pr/xmalloc.c
@@ -0,0 +1,88 @@
+/* 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
+#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
+
+#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, "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. */
+
+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, "virtual memory exhausted");
+ return p;
+}
diff --git a/gnu/usr.bin/ptx/Makefile b/gnu/usr.bin/ptx/Makefile
index b778f7a..340c09a 100644
--- a/gnu/usr.bin/ptx/Makefile
+++ b/gnu/usr.bin/ptx/Makefile
@@ -1,7 +1,10 @@
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+= ${GNUREGEX}
CFLAGS+= -DHAVE_CONFIG_H -DDEFAULT_IGNORE_FILE=\"/usr/share/dict/eign\"
+NOMAN=
+
.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/ptx/regex.h b/gnu/usr.bin/ptx/regex.h
new file mode 100644
index 0000000..a495005
--- /dev/null
+++ b/gnu/usr.bin/ptx/regex.h
@@ -0,0 +1,490 @@
+/* Definitions for data structures and routines for the regular
+ expression library, version 0.12.
+
+ Copyright (C) 1985, 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __REGEXP_LIBRARY_H__
+#define __REGEXP_LIBRARY_H__
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+ <regex.h>. */
+
+#ifdef VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+ should be there. */
+#include <stddef.h>
+#endif
+
+
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* 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 (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions, of course).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+
+ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+ POSIX draft 11.2 says that * etc. in leading positions is undefined.
+ We already implemented a previous draft which made those constructs
+ invalid, though, so we haven't changed the code back. */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+ than the starting range point, as in [z-a], is invalid.
+ If not set, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t re_syntax_options;
+
+/* Define combinations of the above bits for the standard possibilities.
+ (The [[[ comments delimit what gets put into the Texinfo file, so
+ don't delete them!) */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
+ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
+ | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP \
+ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _RE_SYNTAX_POSIX_COMMON \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+ replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow. Some systems
+ (erroneously) define this in other header files, but we want our
+ value, so remove any previous define. */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+#define RE_DUP_MAX ((1 << 15) - 1)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp'). */
+
+/* If this bit is set, then use extended regular expression syntax.
+ If not set, then use basic regular expression syntax. */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+ characters in the string.
+ If not set, then anchors do match at newlines. */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+ If not set, then returns differ between not matching and errors. */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec). */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+ the beginning of the string (presumably because it's not the
+ beginning of a line).
+ If not set, then the beginning-of-line operator does match the
+ beginning of the string. */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line. */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Not implemented. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `no_sub' can be set. After the pattern has been
+ compiled, the `re_nsub' field is available. All other fields are
+ private to the regex routines. */
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+ /* Space that holds the compiled pattern. It is declared as
+ `unsigned char *' because its elements are
+ sometimes used as array indexes. */
+ unsigned char *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t syntax;
+
+ /* Pointer to a fastmap, if any, otherwise zero. re_search uses
+ the fastmap, if there is one, to skip over impossible
+ starting points for matches. */
+ char *fastmap;
+
+ /* Either a translate table to apply to all characters before
+ comparing them, or zero for no translation. The translation
+ is applied to a pattern when it is compiled and to a string
+ when it is matched. */
+ char *translate;
+
+ /* Number of subexpressions found by the compiler. */
+ size_t re_nsub;
+
+ /* Zero if this pattern cannot match the empty string, one else.
+ Well, in truth it's used only in `re_search_2', to see
+ whether or not we should use the fastmap, so we don't set
+ this absolutely perfectly; see `re_compile_fastmap' (the
+ `duplicate' case). */
+ unsigned can_be_null : 1;
+
+ /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+ for `max (RE_NREGS, re_nsub + 1)' groups.
+ If REGS_REALLOCATE, reallocate space if necessary.
+ If REGS_FIXED, use what's there. */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+ unsigned regs_allocated : 2;
+
+ /* Set to zero when `regex_compile' compiles a pattern; set to one
+ by `re_compile_fastmap' if it updates the fastmap. */
+ unsigned fastmap_accurate : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the
+ beginning of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+
+/* search.c (search_buffer) in Emacs needs this one opcode value. It is
+ defined both in `regex.c' and here. */
+#define RE_EXACTN_VALUE 1
+
+/* Type for byte offsets within the string. POSIX mandates this. */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+ `re_match_2' returns information about at least this many registers
+ the first time a `regs' structure is passed. */
+#ifndef RE_NREGS
+#define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers. Aside from the different names than
+ `re_registers', POSIX uses an array of structures, instead of a
+ structure of arrays. */
+typedef struct
+{
+ regoff_t rm_so; /* Byte offset from string's start to substring's start. */
+ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
+} regmatch_t;
+
+/* Declarations for routines. */
+
+/* To avoid duplicating every routine declaration -- once with a
+ prototype (if we are ANSI), and once without (if we aren't) -- we
+ use the following macro to declare argument types. This
+ unfortunately clutters up the declarations a bit, but I think it's
+ worth it. */
+
+#if __STDC__
+
+#define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+#define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+ You can also simply assign to the `re_syntax_options' variable. */
+extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+/* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `re_syntax_options', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+extern const char *re_compile_pattern
+ _RE_ARGS ((const char *pattern, int length,
+ struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+ compiled into BUFFER. Start searching at position START, for RANGE
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->no_sub are nonzero). */
+extern int re_search
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+extern int re_search_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int re_match
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int re_match_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using BUFFER and REGS will use this memory
+ for recording register information. STARTS and ENDS must be
+ allocated with malloc, 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. */
+extern void re_set_registers
+ _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+ unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+/* 4.2 bsd compatibility. */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+
+/* POSIX compatibility. */
+extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
+extern int regexec
+ _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags));
+extern size_t regerror
+ _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
+ size_t errbuf_size));
+extern void regfree _RE_ARGS ((regex_t *preg));
+
+#endif /* not __REGEXP_LIBRARY_H__ */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
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/ci/Makefile b/gnu/usr.bin/rcs/ci/Makefile
index 9b64e08..3ac3d29 100644
--- a/gnu/usr.bin/rcs/ci/Makefile
+++ b/gnu/usr.bin/rcs/ci/Makefile
@@ -1,7 +1,8 @@
-PROG= ci
-
+PROG= ci
SRCS= ci.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/co/Makefile b/gnu/usr.bin/rcs/co/Makefile
index e9de8da..a759d1f 100644
--- a/gnu/usr.bin/rcs/co/Makefile
+++ b/gnu/usr.bin/rcs/co/Makefile
@@ -1,7 +1,8 @@
-PROG= co
-
+PROG= co
SRCS= co.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/co/co.1 b/gnu/usr.bin/rcs/co/co.1
index d9ce65e..1fce152 100644
--- a/gnu/usr.bin/rcs/co/co.1
+++ b/gnu/usr.bin/rcs/co/co.1
@@ -2,7 +2,7 @@
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: co.1,v 5.7 1991/08/19 03:13:55 eggert Exp $
+.Id $Id: co.1,v 1.1.1.1 1993/06/18 04:22:11 jkh Exp $
.ds g \&\s-1UTC\s0
.ds r \&\s-1RCS\s0
.if n .ds - \%--
@@ -141,6 +141,14 @@ See also
.SM "FILE MODES"
below.
.TP
+.B \-K\f2keywordlist\fP
+Exclude or include keyword expansion when checking out a file.
+By default all keywords are expanded, you can turn individual
+keywords off with
+.BR \-K\f2eKeyword\fP
+or on with
+.BR \-K\f2iKeyword\fP .
+.TP
.B \-kkv
Generate keyword strings using the default form, e.g.\&
.B "$\&Revision: \*(Rv $"
diff --git a/gnu/usr.bin/rcs/co/co.c b/gnu/usr.bin/rcs/co/co.c
index 9435574..82f7cc8 100644
--- a/gnu/usr.bin/rcs/co/co.c
+++ b/gnu/usr.bin/rcs/co/co.c
@@ -34,6 +34,9 @@ Report problems and direct all questions to:
/* $Log: co.c,v $
+ * Revision 1.1.1.1 1993/06/18 04:22:11 jkh
+ * Updated GNU utilities
+ *
* 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.
@@ -152,7 +155,7 @@ static void cleanup P((void));
static char const quietarg[] = "-q";
-static char const *expandarg, *join, *suffixarg, *versionarg;
+static char const *expandarg, *join, *suffixarg, *versionarg, *incexcarg;
static char const *joinlist[joinlength]; /* revisions to be joined */
static FILE *neworkptr;
static int exitstatus;
@@ -164,7 +167,7 @@ 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.1.1.1 1993/06/18 04:22:11 jkh Exp $")
{
static char const cmdusage[] =
"\nco usage: co -{flpqru}[rev] -ddate -jjoinlist -sstate -w[login] -Vn file ...";
@@ -270,6 +273,10 @@ mainProg(coId, "co", "$Id: co.c,v 5.9 1991/10/07 17:32:46 eggert Exp $")
setRCSversion(versionarg);
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');
diff --git a/gnu/usr.bin/rcs/ident/Makefile b/gnu/usr.bin/rcs/ident/Makefile
index 1a618e5..25e028b 100644
--- a/gnu/usr.bin/rcs/ident/Makefile
+++ b/gnu/usr.bin/rcs/ident/Makefile
@@ -1,7 +1,8 @@
-PROG= ident
-
+PROG= ident
SRCS= ident.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/lib/Makefile b/gnu/usr.bin/rcs/lib/Makefile
index b198e9e..a69000b 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 rcsutil.c \
+ merger.c
+
+NOPROFILE=noprofile
+
+install:
.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/rcs/lib/rcsbase.h b/gnu/usr.bin/rcs/lib/rcsbase.h
index c0904bb..17a123d 100644
--- a/gnu/usr.bin/rcs/lib/rcsbase.h
+++ b/gnu/usr.bin/rcs/lib/rcsbase.h
@@ -2,7 +2,7 @@
/*
* 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.1.1.1 1993/06/18 04:22:13 jkh Exp $"
/* Copyright (C) 1982, 1988, 1989 Walter Tichy
Copyright 1990, 1991 by Paul Eggert
@@ -43,6 +43,9 @@ Report problems and direct all questions to:
/* $Log: rcsbase.h,v $
+ * Revision 1.1.1.1 1993/06/18 04:22:13 jkh
+ * Updated GNU utilities
+ *
* Revision 5.11 1991/10/07 17:32:46 eggert
* Support piece tables even if !has_mmap.
*
@@ -380,10 +383,11 @@ struct assoc {
#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, 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"
diff --git a/gnu/usr.bin/rcs/lib/rcsedit.c b/gnu/usr.bin/rcs/lib/rcsedit.c
index fab4f62..98e4c4b 100644
--- a/gnu/usr.bin/rcs/lib/rcsedit.c
+++ b/gnu/usr.bin/rcs/lib/rcsedit.c
@@ -36,6 +36,9 @@ Report problems and direct all questions to:
/* $Log: rcsedit.c,v $
+ * Revision 1.1.1.1 1993/06/18 04:22:12 jkh
+ * Updated GNU utilities
+ *
* Revision 5.11 1991/11/03 01:11:44 eggert
* Move the warning about link breaking to where they're actually being broken.
*
@@ -154,7 +157,7 @@ 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 $")
+libId(editId, "$Id: rcsedit.c,v 1.1.1.1 1993/06/18 04:22:12 jkh Exp $")
static void keyreplace P((enum markers,struct hshentry const*,FILE*));
@@ -959,10 +962,14 @@ keyreplace(marker,delta,out)
case Date:
aputs(date2str(date,datebuf), out);
break;
+ /*
+ * The FreeBSD keyword is identical to Id.
+ */
+ case FreeBSD:
case Id:
case Header:
aprintf(out, "%s %s %s %s %s",
- marker==Id || RCSv<VERSION(4)
+ marker==Id || marker==FreeBSD || RCSv<VERSION(4)
? basename(RCSfilename)
: getfullRCSname(),
delta->num,
diff --git a/gnu/usr.bin/rcs/lib/rcskeys.c b/gnu/usr.bin/rcs/lib/rcskeys.c
index 82850a7..cb80314 100644
--- a/gnu/usr.bin/rcs/lib/rcskeys.c
+++ b/gnu/usr.bin/rcs/lib/rcskeys.c
@@ -31,6 +31,19 @@ Report problems and direct all questions to:
/* $Log: rcskeys.c,v $
+ * Revision 1.3 1994/05/15 22:15:14 rgrimes
+ * To truely have the OLD behavior of RCS by default make the expansion
+ * of $FreeBSD$ false by default. This should keep them out
+ * of the pre 2.x repository. (Or at least make them useless in it).
+ *
+ * Revision 1.2 1994/05/14 07:00:23 rgrimes
+ * Add new option -K from David Dawes that allows you to turn on and off
+ * specific keyword substitution during a rcs co command.
+ * Add the new keyword FreeBSD that is IDENTICAL in operation to $Id: rcskeys.c,v 1.3 1994/05/15 22:15:14 rgrimes Exp $.
+ *
+ * Revision 1.1.1.1 1993/06/18 04:22:12 jkh
+ * Updated GNU utilities
+ *
* 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.)
@@ -60,17 +73,26 @@ Report problems and direct all questions to:
#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.3 1994/05/15 22:15:14 rgrimes Exp $")
char const *const Keyword[] = {
/* This must be in the same order as rcsbase.h's enum markers type. */
nil,
AUTHOR, DATE, HEADER, IDH,
- LOCKER, LOG, RCSFILE, REVISION, SOURCE, STATE
+ LOCKER, LOG, RCSFILE, REVISION, SOURCE, STATE,
+ FREEBSD
};
+/* Expand all keywords by default */
+
+static int ExpandKeyword[] = {
+ nil,
+ true, true, true, true,
+ true, true, true, true, true, true,
+ false
+};
enum markers
trymatch(string)
@@ -83,6 +105,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 +124,35 @@ 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..cedbc40 100644
--- a/gnu/usr.bin/rcs/lib/rcslex.c
+++ b/gnu/usr.bin/rcs/lib/rcslex.c
@@ -39,6 +39,9 @@ Report problems and direct all questions to:
/* $Log: rcslex.c,v $
+ * Revision 1.1.1.1 1993/06/18 04:22:12 jkh
+ * Updated GNU utilities
+ *
* Revision 5.11 1991/11/03 03:30:44 eggert
* Fix porting bug to ancient hosts lacking vfprintf.
*
@@ -132,7 +135,7 @@ 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.1.1.1 1993/06/18 04:22:12 jkh Exp $")
static struct hshentry *nexthsh; /*pointer to next hash entry, set by lookup*/
@@ -935,7 +938,13 @@ void testIerror(f) FILE *f; { if (ferror(f)) Ierror(); }
void testOerror(o) FILE *o; { if (ferror(o)) Oerror(); }
void Ifclose(f) RILE *f; { if (f && Iclose(f)!=0) Ierror(); }
+#ifndef FSYNC_ALL
void Ofclose(f) FILE *f; { if (f && fclose(f)!=0) Oerror(); }
+#else
+void Ofclose(f) FILE *f; { if (f && (fflush(f)!=0 ||
+ fsync(fileno(f))!=0 ||
+ fclose(f)!=0)) Oerror(); }
+#endif
void Izclose(p) RILE **p; { Ifclose(*p); *p = 0; }
void Ozclose(p) FILE **p; { Ofclose(*p); *p = 0; }
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/rcs/Makefile b/gnu/usr.bin/rcs/rcs/Makefile
index d62c8d1..e3cd12e 100644
--- a/gnu/usr.bin/rcs/rcs/Makefile
+++ b/gnu/usr.bin/rcs/rcs/Makefile
@@ -1,10 +1,11 @@
-PROG= rcs
-
+PROG= rcs
SRCS= rcs.c
-LDADD= -L${.CURDIR}/../lib/obj -lrcs
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/rcsclean/Makefile b/gnu/usr.bin/rcs/rcsclean/Makefile
index fc0c626..2651a3f 100644
--- a/gnu/usr.bin/rcs/rcsclean/Makefile
+++ b/gnu/usr.bin/rcs/rcsclean/Makefile
@@ -1,7 +1,8 @@
-PROG= rcsclean
-
+PROG= rcsclean
SRCS= rcsclean.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/rcsdiff/Makefile b/gnu/usr.bin/rcs/rcsdiff/Makefile
index 837c241..070e231 100644
--- a/gnu/usr.bin/rcs/rcsdiff/Makefile
+++ b/gnu/usr.bin/rcs/rcsdiff/Makefile
@@ -1,7 +1,8 @@
-PROG= rcsdiff
-
+PROG= rcsdiff
SRCS= rcsdiff.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/rcsfreeze/Makefile b/gnu/usr.bin/rcs/rcsfreeze/Makefile
index 825d4bf..c1b4841 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/rcsmerge/Makefile b/gnu/usr.bin/rcs/rcsmerge/Makefile
index 0c1f643..801b01e 100644
--- a/gnu/usr.bin/rcs/rcsmerge/Makefile
+++ b/gnu/usr.bin/rcs/rcsmerge/Makefile
@@ -1,7 +1,8 @@
-PROG= rcsmerge
-
+PROG= rcsmerge
SRCS= rcsmerge.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/rlog/Makefile b/gnu/usr.bin/rcs/rlog/Makefile
index b6a1268..a1d19aa 100644
--- a/gnu/usr.bin/rcs/rlog/Makefile
+++ b/gnu/usr.bin/rcs/rlog/Makefile
@@ -1,7 +1,8 @@
-PROG= rlog
-
+PROG= rlog
SRCS= rlog.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/rlog/rlog.1 b/gnu/usr.bin/rcs/rlog/rlog.1
index fa627ff..e3deb68 100644
--- a/gnu/usr.bin/rcs/rlog/rlog.1
+++ b/gnu/usr.bin/rcs/rlog/rlog.1
@@ -2,7 +2,7 @@
.ds Rv \\$3
.ds Dt \\$4
..
-.Id $Id: rlog.1,v 5.3 1991/08/22 06:50:48 eggert Exp $
+.Id $Id: rlog.1,v 1.2 1994/05/11 22:39:43 phk Exp $
.ds g \&\s-1UTC\s0
.ds r \&\s-1RCS\s0
.if n .ds - \%--
@@ -54,6 +54,10 @@ Print only the name of the \*r file.
This is convenient for translating a
working pathname into an \*r pathname.
.TP
+.BI \-v "[string]"
+Print only the working pathname and tip-revision.
+The optional string is prepended to the outputline.
+.TP
.B \-h
Print only the \*r pathname, working pathname, head,
default branch, access list, locks,
diff --git a/gnu/usr.bin/rcs/rlog/rlog.c b/gnu/usr.bin/rcs/rlog/rlog.c
index b18b0c9..bf59e66 100644
--- a/gnu/usr.bin/rcs/rlog/rlog.c
+++ b/gnu/usr.bin/rcs/rlog/rlog.c
@@ -36,6 +36,19 @@ Report problems and direct all questions to:
/* $Log: rlog.c,v $
+ * Revision 1.4 1994/05/12 00:37:59 phk
+ * made -v produce tip-revision, which was what I wanted in the first place...
+ *
+ * Revision 1.3 1994/05/11 22:39:44 phk
+ * Added -v option to rlog. This gives a quick way to get a list of versions.
+ *
+ * Revision 1.2 1993/08/06 16:47:16 nate
+ * Have rlog output be much easier to parse. (Added one line which is not
+ * used by any CVS/RCS commands)
+ *
+ * Revision 1.1.1.1 1993/06/18 04:22:17 jkh
+ * Updated GNU utilities
+ *
* Revision 5.9 1991/09/17 19:07:40 eggert
* Getscript() didn't uncache partial lines.
*
@@ -191,10 +204,10 @@ static struct lockers *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.4 1994/05/12 00:37:59 phk Exp $")
{
static char const cmdusage[] =
- "\nrlog usage: rlog -{bhLRt} -ddates -l[lockers] -rrevs -sstates -w[logins] -Vn file ...";
+ "\nrlog usage: rlog -{bhLRt} [-v[string]] -ddates -l[lockers] -rrevs -sstates -w[logins] -Vn file ...";
register FILE *out;
char *a, **newargv;
@@ -207,11 +220,14 @@ mainProg(rlogId, "rlog", "$Id: rlog.c,v 5.9 1991/09/17 19:07:40 eggert Exp $")
struct lock const *currlock;
int descflag, selectflag;
int onlylockflag; /* print only files with locks */
+ int versionlist;
+ char *vstring;
int onlyRCSflag; /* print only RCS file name */
unsigned revno;
descflag = selectflag = true;
- onlylockflag = onlyRCSflag = false;
+ versionlist = onlylockflag = onlyRCSflag = false;
+ vstring=0;
out = stdout;
suffixes = X_DEFAULT;
@@ -274,6 +290,11 @@ mainProg(rlogId, "rlog", "$Id: rlog.c,v 5.9 1991/09/17 19:07:40 eggert Exp $")
setRCSversion(*argv);
break;
+ case 'v':
+ versionlist = true;
+ vstring = a;
+ break;
+
default:
faterror("unknown option: %s%s", *argv, cmdusage);
@@ -323,6 +344,12 @@ 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, workfilename, tiprev());
+ continue;
+ }
+
if ( onlyRCSflag ) {
aprintf(out, "%s\n", RCSfilename);
continue;
@@ -402,6 +429,7 @@ mainProg(rlogId, "rlog", "$Id: rlog.c,v 5.9 1991/09/17 19:07:40 eggert Exp $")
putrunk();
putree(Head);
}
+ aputs("----------------------------\n", out);
aputs("=============================================================================\n",out);
} while (cleanup(),
++argv, --argc >= 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/sort/Makefile b/gnu/usr.bin/sort/Makefile
new file mode 100644
index 0000000..f4e2f88
--- /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 -DDHAVE_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 e849c5b..41d66fb 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, 1991, 1992 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
@@ -17,6 +17,17 @@
/* 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>
#ifdef HAVE_VPRINTF
diff --git a/gnu/usr.bin/sort/sort.1 b/gnu/usr.bin/sort/sort.1
index 3acc398..19532c8 100644
--- a/gnu/usr.bin/sort/sort.1
+++ b/gnu/usr.bin/sort/sort.1
@@ -5,6 +5,9 @@ sort \- sort lines of text files
.B sort
[\-cmus] [\-t separator] [\-o output-file] [\-T tempdir] [\-bdfiMnr]
[+POS1 [\-POS2]] [\-k POS1[,POS2]] [file...]
+.br
+.B sort
+{\-\-help,\-\-version}
.SH DESCRIPTION
This manual page
documents the GNU version of
@@ -187,6 +190,16 @@ option, the
.I \-b
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 join
+is invoked with exactly one argument, the following options are recognized:
+.TP
+.I "\-\-help"
+Print a usage message on standard output and exit successfully.
+.TP
+.I "\-\-version"
+Print version information on standard output then exit successfully.
.SH COMPATIBILITY
.PP
Historical (BSD and System V) implementations of
diff --git a/gnu/usr.bin/sort/sort.c b/gnu/usr.bin/sort/sort.c
index 42e0b8e..74d4b46 100644
--- a/gnu/usr.bin/sort/sort.c
+++ b/gnu/usr.bin/sort/sort.c
@@ -19,6 +19,17 @@
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
@@ -26,6 +37,8 @@
#include <signal.h>
#include <stdio.h>
#include "system.h"
+#include "long-options.h"
+
#ifdef _POSIX_VERSION
#include <limits.h>
#else
@@ -1447,6 +1460,9 @@ main (argc, argv)
#endif /* _POSIX_VERSION */
program_name = argv[0];
+
+ parse_long_options (argc, argv, usage);
+
have_read_stdin = 0;
inittables ();
@@ -1528,7 +1544,7 @@ main (argc, argv)
if (digits[UCHAR (*s)])
{
if (!key)
- usage ();
+ usage (2);
for (t = 0; digits[UCHAR (*s)]; ++s)
t = t * 10 + *s - '0';
t2 = 0;
@@ -1662,10 +1678,14 @@ main (argc, argv)
case 'u':
unique = 1;
break;
+ case 'y':
+ /* Accept and ignore e.g. -y0 for compatibility with
+ Solaris 2. */
+ goto outer;
default:
fprintf (stderr, "%s: unrecognized option `-%c'\n",
argv[0], *s);
- usage ();
+ usage (2);
}
if (*s)
++s;
@@ -1764,11 +1784,46 @@ main (argc, argv)
}
static void
-usage ()
+usage (status)
+ int status;
{
- fprintf (stderr, "\
-Usage: %s [-cmus] [-t separator] [-o output-file] [-T tempdir] [-bdfiMnr]\n\
- [+POS1 [-POS2]] [-k POS1[,POS2]] [file...]\n",
- program_name);
- exit (2);
+ 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 2e03ea8..4aeaaea 100644
--- a/gnu/usr.bin/sort/system.h
+++ b/gnu/usr.bin/sort/system.h
@@ -18,6 +18,40 @@
/* Include sys/types.h before this file. */
#include <sys/stat.h>
+
+#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
+#endif /* STAT_MACROS_BROKEN. */
+
#ifndef S_ISREG /* Doesn't have POSIX.1 stat stuff. */
#define mode_t unsigned short
#endif
diff --git a/gnu/usr.bin/tar/Makefile b/gnu/usr.bin/tar/Makefile
index 810fe3b..cab7e00 100644
--- a/gnu/usr.bin/tar/Makefile
+++ b/gnu/usr.bin/tar/Makefile
@@ -8,7 +8,9 @@ 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+= -DDEF_AR_FILE=\"/dev/rst0\" -DDEFBLOCKING=20
+CLEANFILES+=y.tab.h
NOMAN=noman
+NOSHARED=yes
.include <bsd.prog.mk>
.include "../../usr.bin/Makefile.inc"
diff --git a/gnu/usr.bin/tar/extract.c b/gnu/usr.bin/tar/extract.c
index d162cab..57f8222 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)
diff --git a/gnu/usr.bin/tar/tar.c b/gnu/usr.bin/tar/tar.c
index 9382582..ec2c3d1 100644
--- a/gnu/usr.bin/tar/tar.c
+++ b/gnu/usr.bin/tar/tar.c
@@ -181,6 +181,8 @@ struct option long_options[] =
{"force-local", 0, &f_force_local, 1},
{"atime-preserve", 0, &f_atime_preserve, 1},
+ {"unlink", 0, &f_unlink, 1},
+
{0, 0, 0, 0}
};
@@ -757,6 +759,7 @@ 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\
", stdout);
}
diff --git a/gnu/usr.bin/tar/tar.h b/gnu/usr.bin/tar/tar.h
index c3fec78..46d29d8 100644
--- a/gnu/usr.bin/tar/tar.h
+++ b/gnu/usr.bin/tar/tar.h
@@ -231,6 +231,7 @@ 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 */
/*
* We default to Unix Standard format rather than 4.2BSD tar format.
OpenPOWER on IntegriCloud